14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/* 24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project 34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License. 64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at 74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * 104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software 114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and 144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License. 154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */ 164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 17a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslavpackage com.android.printspooler.model; 184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 19b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmannimport android.annotation.FloatRange; 20b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmannimport android.annotation.NonNull; 21b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmannimport android.annotation.Nullable; 22d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmannimport android.annotation.StringRes; 234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Service; 244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName; 25a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslavimport android.content.Context; 264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent; 27bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmannimport android.graphics.drawable.Icon; 28269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.os.AsyncTask; 29b4fda134761c9521a7e127db3806a07a18763b77Svetoslavimport android.os.Bundle; 304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.IBinder; 314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message; 324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.ParcelFileDescriptor; 334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException; 34a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpooler; 35a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerCallbacks; 36835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.print.IPrintSpoolerClient; 37269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PageRange; 384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintAttributes; 39269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Margins; 40269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.MediaSize; 41269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Resolution; 42269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintDocumentInfo; 432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId; 444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo; 45269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintManager; 46269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrinterId; 47a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslavimport android.text.TextUtils; 48dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport android.util.ArrayMap; 49269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.AtomicFile; 50835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.util.Log; 514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Slog; 52269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.Xml; 534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 54dcc34fd8a3f718e5e5cfaccb87eeffd64ac80f63Chris Wrenimport com.android.internal.logging.MetricsLogger; 55269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.os.HandlerCaller; 56269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.util.FastXmlSerializer; 57a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslavimport com.android.printspooler.R; 58853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmannimport com.android.printspooler.util.ApprovedPrintServices; 594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport libcore.io.IoUtils; 612fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav 62269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParser; 63269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParserException; 64269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlSerializer; 65269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 66269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.File; 67dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.FileDescriptor; 68269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileInputStream; 69269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileNotFoundException; 70269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileOutputStream; 71269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.IOException; 72dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.PrintWriter; 739e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewiczimport java.nio.charset.StandardCharsets; 74269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.util.ArrayList; 75835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport java.util.List; 76853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmannimport java.util.Set; 77835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/** 794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Service for exposing some of the {@link PrintSpooler} functionality to 804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * another process. 814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */ 824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic final class PrintSpoolerService extends Service { 834b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 84269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String LOG_TAG = "PrintSpoolerService"; 85269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 86b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false; 87269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 88c6066799ad130140159230d14451b429eb828755Svetoslav private static final boolean DEBUG_PERSISTENCE = false; 89269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 904237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov private static final boolean PERSISTENCE_MANAGER_ENABLED = true; 91269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 92835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000; 93835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 94dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov private static final String PRINT_JOB_FILE_PREFIX = "print_job_"; 95dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 96269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String PRINT_FILE_EXTENSION = "pdf"; 97269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 98269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final Object sLock = new Object(); 99269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private final Object mLock = new Object(); 101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 102a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav private final List<PrintJobInfo> mPrintJobs = new ArrayList<>(); 103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static PrintSpoolerService sInstance; 105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 106835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov private IPrintSpoolerClient mClient; 1074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private HandlerCaller mHandlerCaller; 109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private PersistenceManager mPersistanceManager; 111269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private NotificationController mNotificationController; 113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 114bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann /** Cache for custom printer icons loaded from the print service */ 115bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann private CustomPrinterIconCache mCustomIconCache; 116bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public static PrintSpoolerService peekInstance() { 118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (sLock) { 119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return sInstance; 120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 1234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov @Override 1244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov public void onCreate() { 1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov super.onCreate(); 126269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mHandlerCaller = new HandlerCaller(this, getMainLooper(), 127269403b032f965ff3847eb982c2f697229dc5a92Svetoslav new HandlerCallerCallback(), false); 128269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 129269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPersistanceManager = new PersistenceManager(); 130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mNotificationController = new NotificationController(PrintSpoolerService.this); 131bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann mCustomIconCache = new CustomPrinterIconCache(getCacheDir()); 132269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 133269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPersistanceManager.readStateLocked(); 135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav handleReadPrintJobsLocked(); 136269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 137269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 138269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (sLock) { 139269403b032f965ff3847eb982c2f697229dc5a92Svetoslav sInstance = this; 140269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov @Override 144bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void onDestroy() { 145bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann super.onDestroy(); 146bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 147bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 148bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann @Override 1494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov public IBinder onBind(Intent intent) { 1507bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav return new PrintSpooler(); 1514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 1524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 153dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov @Override 154dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 155853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann String prefix = (args.length > 0) ? args[0] : ""; 156853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann String tab = " "; 157dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 158853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann synchronized (mLock) { 159dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov pw.append(prefix).append("print jobs:").println(); 160dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov final int printJobCount = mPrintJobs.size(); 161dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov for (int i = 0; i < printJobCount; i++) { 162dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov PrintJobInfo printJob = mPrintJobs.get(i); 163dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov pw.append(prefix).append(tab).append(printJob.toString()); 164dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov pw.println(); 165dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 166dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 167dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov pw.append(prefix).append("print job files:").println(); 168dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov File[] files = getFilesDir().listFiles(); 169dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (files != null) { 170dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov final int fileCount = files.length; 171dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov for (int i = 0; i < fileCount; i++) { 172dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov File file = files[i]; 173dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) { 174dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov pw.append(prefix).append(tab).append(file.getName()).println(); 175dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 176dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 177dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 178dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 179853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann 180853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann pw.append(prefix).append("approved print services:").println(); 181853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann Set<String> approvedPrintServices = (new ApprovedPrintServices(this)).getApprovedServices(); 182853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann if (approvedPrintServices != null) { 183853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann for (String approvedService : approvedPrintServices) { 184853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann pw.append(prefix).append(tab).append(approvedService).println(); 185853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann } 186853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann } 187dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 188dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 189269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void sendOnPrintJobQueued(PrintJobInfo printJob) { 190269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Message message = mHandlerCaller.obtainMessageO( 191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob); 192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mHandlerCaller.executeOrSendMessage(message); 193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void sendOnAllPrintJobsForServiceHandled(ComponentName service) { 196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Message message = mHandlerCaller.obtainMessageO( 197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service); 198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mHandlerCaller.executeOrSendMessage(message); 199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 201269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void sendOnAllPrintJobsHandled() { 202269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Message message = mHandlerCaller.obtainMessage( 203269403b032f965ff3847eb982c2f697229dc5a92Svetoslav HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED); 204269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mHandlerCaller.executeOrSendMessage(message); 205269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 206269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 207269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private final class HandlerCallerCallback implements HandlerCaller.Callback { 208704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov public static final int MSG_SET_CLIENT = 1; 2097bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public static final int MSG_ON_PRINT_JOB_QUEUED = 2; 2107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 3; 2117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 4; 2127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 5; 2137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 6; 2144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov 2154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov @Override 216269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public void executeMessage(Message message) { 217835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov switch (message.what) { 218835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov case MSG_SET_CLIENT: { 219269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 220269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mClient = (IPrintSpoolerClient) message.obj; 221269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (mClient != null) { 222269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Message msg = mHandlerCaller.obtainMessage( 223269403b032f965ff3847eb982c2f697229dc5a92Svetoslav HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED); 224269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mHandlerCaller.sendMessageDelayed(msg, 225269403b032f965ff3847eb982c2f697229dc5a92Svetoslav CHECK_ALL_PRINTJOBS_HANDLED_DELAY); 226269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 227835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 228835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } break; 229835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 230835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov case MSG_ON_PRINT_JOB_QUEUED: { 231835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov PrintJobInfo printJob = (PrintJobInfo) message.obj; 232835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov if (mClient != null) { 233835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov try { 234835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov mClient.onPrintJobQueued(printJob); 235835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } catch (RemoteException re) { 236835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov Slog.e(LOG_TAG, "Error notify for a queued print job.", re); 237835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 238835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 239835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } break; 240835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 241835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: { 242835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov ComponentName service = (ComponentName) message.obj; 243835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov if (mClient != null) { 244835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov try { 245835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov mClient.onAllPrintJobsForServiceHandled(service); 246835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } catch (RemoteException re) { 247835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov Slog.e(LOG_TAG, "Error notify for all print jobs per service" 248835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov + " handled.", re); 249835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 250835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 251835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } break; 252835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 253835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov case MSG_ON_ALL_PRINT_JOBS_HANDLED: { 254835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov if (mClient != null) { 255835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov try { 256835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov mClient.onAllPrintJobsHandled(); 257835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } catch (RemoteException re) { 258835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov Slog.e(LOG_TAG, "Error notify for all print job handled.", re); 259835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 260835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } 261835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov } break; 262835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov 263835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov case MSG_CHECK_ALL_PRINTJOBS_HANDLED: { 264269403b032f965ff3847eb982c2f697229dc5a92Svetoslav checkAllPrintJobsHandled(); 265269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } break; 266704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov 267704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov case MSG_ON_PRINT_JOB_STATE_CHANGED: { 268704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov if (mClient != null) { 269dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov PrintJobInfo printJob = (PrintJobInfo) message.obj; 270704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov try { 271dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov mClient.onPrintJobStateChanged(printJob); 272704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } catch (RemoteException re) { 273704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov Slog.e(LOG_TAG, "Error notify for print job state change.", re); 274704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } 275704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } 276704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } break; 2774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 2784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 2794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov } 280269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 281269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, 282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav int state, int appId) { 283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav List<PrintJobInfo> foundPrintJobs = null; 284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 285269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = mPrintJobs.size(); 286269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < printJobCount; i++) { 287269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 288269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrinterId printerId = printJob.getPrinterId(); 289269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final boolean sameComponent = (componentName == null 290269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || (printerId != null 291269403b032f965ff3847eb982c2f697229dc5a92Svetoslav && componentName.equals(printerId.getServiceName()))); 292269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final boolean sameAppId = appId == PrintManager.APP_ID_ANY 293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || printJob.getAppId() == appId; 294269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final boolean sameState = (state == printJob.getState()) 295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || (state == PrintJobInfo.STATE_ANY) 296269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS 297d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov && isStateVisibleToUser(printJob.getState())) 298d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov || (state == PrintJobInfo.STATE_ANY_ACTIVE 2999b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov && isActiveState(printJob.getState())) 3009b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov || (state == PrintJobInfo.STATE_ANY_SCHEDULED 3019b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov && isScheduledState(printJob.getState())); 302269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (sameComponent && sameAppId && sameState) { 303269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (foundPrintJobs == null) { 304a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav foundPrintJobs = new ArrayList<>(); 305269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 306269403b032f965ff3847eb982c2f697229dc5a92Svetoslav foundPrintJobs.add(printJob); 307269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 308269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 309269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 310269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return foundPrintJobs; 311269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 312269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 313d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov private boolean isStateVisibleToUser(int state) { 314d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED 3152fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED 3162fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav || state == PrintJobInfo.STATE_BLOCKED)); 317d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov } 318d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov 3192fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) { 320269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 321269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = mPrintJobs.size(); 322269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < printJobCount; i++) { 323269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 3242fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav if (printJob.getId().equals(printJobId) 325269403b032f965ff3847eb982c2f697229dc5a92Svetoslav && (appId == PrintManager.APP_ID_ANY 326269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || appId == printJob.getAppId())) { 327269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return printJob; 328269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 329269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 330269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return null; 331269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 332269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 333269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 3342fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav public void createPrintJob(PrintJobInfo printJob) { 335269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 336269403b032f965ff3847eb982c2f697229dc5a92Svetoslav addPrintJobLocked(printJob); 337dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null); 3387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 3397bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav Message message = mHandlerCaller.obtainMessageO( 3407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, 3417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav printJob); 3427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav mHandlerCaller.executeOrSendMessage(message); 343269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 344269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void handleReadPrintJobsLocked() { 347dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // Make a map with the files for a print job since we may have 348dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // to delete some. One example of getting orphan files if the 349dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // spooler crashes while constructing a print job. We do not 350dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // persist partially populated print jobs under construction to 351dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // avoid special handling for various attributes missing. 352dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov ArrayMap<PrintJobId, File> fileForJobMap = null; 353dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov File[] files = getFilesDir().listFiles(); 354dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (files != null) { 355dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov final int fileCount = files.length; 356dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov for (int i = 0; i < fileCount; i++) { 357dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov File file = files[i]; 358dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) { 359dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (fileForJobMap == null) { 360dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov fileForJobMap = new ArrayMap<PrintJobId, File>(); 361dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 3622b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov String printJobIdString = file.getName().substring( 3632b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov PRINT_JOB_FILE_PREFIX.length(), 3642b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov file.getName().indexOf('.')); 365dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov PrintJobId printJobId = PrintJobId.unflattenFromString( 366dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov printJobIdString); 367dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov fileForJobMap.put(printJobId, file); 368dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 369dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 370dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 371dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 372269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = mPrintJobs.size(); 373269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < printJobCount; i++) { 374269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 375269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 376dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // We want to have only the orphan files at the end. 377dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (fileForJobMap != null) { 378dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov fileForJobMap.remove(printJob.getId()); 379dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 380dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 381269403b032f965ff3847eb982c2f697229dc5a92Svetoslav switch (printJob.getState()) { 382269403b032f965ff3847eb982c2f697229dc5a92Svetoslav case PrintJobInfo.STATE_QUEUED: 383d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov case PrintJobInfo.STATE_STARTED: 384d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov case PrintJobInfo.STATE_BLOCKED: { 385d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov // We have a print job that was queued or started or blocked in 386d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov // the past but the device battery died or a crash occurred. In 387d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov // this case we assume the print job failed and let the user 388d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov // decide whether to restart the job or just cancel it. 389269403b032f965ff3847eb982c2f697229dc5a92Svetoslav setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, 390269403b032f965ff3847eb982c2f697229dc5a92Svetoslav getString(R.string.no_connection_to_printer)); 3912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } break; 392269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 393269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 394dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov 395a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov if (!mPrintJobs.isEmpty()) { 396a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov // Update the notification. 397a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov mNotificationController.onUpdateNotifications(mPrintJobs); 398a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov } 399a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov 400dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov // Delete the orphan files. 401dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov if (fileForJobMap != null) { 402dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov final int orphanFileCount = fileForJobMap.size(); 403dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov for (int i = 0; i < orphanFileCount; i++) { 404dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov File file = fileForJobMap.valueAt(i); 405dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov file.delete(); 406dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 407dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov } 408269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 409269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 410269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public void checkAllPrintJobsHandled() { 411269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 412269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!hasActivePrintJobsLocked()) { 413269403b032f965ff3847eb982c2f697229dc5a92Svetoslav notifyOnAllPrintJobsHandled(); 414269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 415269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 416269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 417269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 4182fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) { 419269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final PrintJobInfo printJob; 420269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 421269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 422269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 423269403b032f965ff3847eb982c2f697229dc5a92Svetoslav new AsyncTask<Void, Void, Void>() { 424269403b032f965ff3847eb982c2f697229dc5a92Svetoslav @Override 425269403b032f965ff3847eb982c2f697229dc5a92Svetoslav protected Void doInBackground(Void... params) { 426269403b032f965ff3847eb982c2f697229dc5a92Svetoslav FileInputStream in = null; 427269403b032f965ff3847eb982c2f697229dc5a92Svetoslav FileOutputStream out = null; 428269403b032f965ff3847eb982c2f697229dc5a92Svetoslav try { 429269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printJob != null) { 430a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId); 431269403b032f965ff3847eb982c2f697229dc5a92Svetoslav in = new FileInputStream(file); 432269403b032f965ff3847eb982c2f697229dc5a92Svetoslav out = new FileOutputStream(fd.getFileDescriptor()); 433269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 434269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final byte[] buffer = new byte[8192]; 435269403b032f965ff3847eb982c2f697229dc5a92Svetoslav while (true) { 436269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int readByteCount = in.read(buffer); 437269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (readByteCount < 0) { 438269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return null; 439269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav out.write(buffer, 0, readByteCount); 441269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 442269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (FileNotFoundException fnfe) { 443269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.e(LOG_TAG, "Error writing print job data!", fnfe); 444269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (IOException ioe) { 445269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.e(LOG_TAG, "Error writing print job data!", ioe); 446269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } finally { 447269403b032f965ff3847eb982c2f697229dc5a92Svetoslav IoUtils.closeQuietly(in); 448269403b032f965ff3847eb982c2f697229dc5a92Svetoslav IoUtils.closeQuietly(out); 449269403b032f965ff3847eb982c2f697229dc5a92Svetoslav IoUtils.closeQuietly(fd); 450269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 451269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.i(LOG_TAG, "[END WRITE]"); 452269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return null; 453269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 454269403b032f965ff3847eb982c2f697229dc5a92Svetoslav }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 455269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 456269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 457a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav public static File generateFileForPrintJob(Context context, PrintJobId printJobId) { 458a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav return new File(context.getFilesDir(), PRINT_JOB_FILE_PREFIX 4592fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION); 460269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 461269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 462269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void addPrintJobLocked(PrintJobInfo printJob) { 463269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPrintJobs.add(printJob); 464269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PRINT_JOB_LIFECYCLE) { 465269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.i(LOG_TAG, "[ADD] " + printJob); 466269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 467269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 468269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 4692fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav private void removeObsoletePrintJobs() { 4702fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav synchronized (mLock) { 471885810de69d75979df4299d21fa236490767eae4Svetoslav boolean persistState = false; 4722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav final int printJobCount = mPrintJobs.size(); 4732fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav for (int i = printJobCount - 1; i >= 0; i--) { 4742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 4752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav if (isObsoleteState(printJob.getState())) { 4762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav mPrintJobs.remove(i); 4772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav if (DEBUG_PRINT_JOB_LIFECYCLE) { 4782fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString()); 4792fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 4802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav removePrintJobFileLocked(printJob.getId()); 481885810de69d75979df4299d21fa236490767eae4Svetoslav persistState = true; 4822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 4832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 484885810de69d75979df4299d21fa236490767eae4Svetoslav if (persistState) { 485885810de69d75979df4299d21fa236490767eae4Svetoslav mPersistanceManager.writeStateLocked(); 486885810de69d75979df4299d21fa236490767eae4Svetoslav } 4872fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 4882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 4892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav 4902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav private void removePrintJobFileLocked(PrintJobId printJobId) { 491a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId); 4922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav if (file.exists()) { 4932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav file.delete(); 494269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PRINT_JOB_LIFECYCLE) { 495dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId); 496269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 497269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 498269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 499269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 5004bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann /** 5014bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann * Notify all interested parties that a print job has been updated. 5024bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann * 5034bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann * @param printJob The updated print job. 5044bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann */ 5054bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann private void notifyPrintJobUpdated(PrintJobInfo printJob) { 5064bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann Message message = mHandlerCaller.obtainMessageO( 5074bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, 5084bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann printJob); 5094bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann mHandlerCaller.executeOrSendMessage(message); 5104bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann 5114bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann mNotificationController.onUpdateNotifications(mPrintJobs); 5124bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann } 5134bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann 5142fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav public boolean setPrintJobState(PrintJobId printJobId, int state, String error) { 515269403b032f965ff3847eb982c2f697229dc5a92Svetoslav boolean success = false; 516269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 518269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 519269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printJob != null) { 520704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov final int oldState = printJob.getState(); 521704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov if (oldState == state) { 522704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov return false; 523704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } 524704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov 525269403b032f965ff3847eb982c2f697229dc5a92Svetoslav success = true; 526269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 527269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setState(state); 528b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann printJob.setStatus(error); 529a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov printJob.setCancelling(false); 530269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 531269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PRINT_JOB_LIFECYCLE) { 532269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob); 533269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 534269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 535dcc34fd8a3f718e5e5cfaccb87eeffd64ac80f63Chris Wren MetricsLogger.histogram(this, "print_job_state", state); 536269403b032f965ff3847eb982c2f697229dc5a92Svetoslav switch (state) { 537269403b032f965ff3847eb982c2f697229dc5a92Svetoslav case PrintJobInfo.STATE_COMPLETED: 538269403b032f965ff3847eb982c2f697229dc5a92Svetoslav case PrintJobInfo.STATE_CANCELED: 539dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov mPrintJobs.remove(printJob); 5402fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav removePrintJobFileLocked(printJob.getId()); 541269403b032f965ff3847eb982c2f697229dc5a92Svetoslav // $fall-through$ 542269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 543269403b032f965ff3847eb982c2f697229dc5a92Svetoslav case PrintJobInfo.STATE_FAILED: { 544269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrinterId printerId = printJob.getPrinterId(); 545269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printerId != null) { 546269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ComponentName service = printerId.getServiceName(); 547269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!hasActivePrintJobsForServiceLocked(service)) { 548269403b032f965ff3847eb982c2f697229dc5a92Svetoslav sendOnAllPrintJobsForServiceHandled(service); 549269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 550269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 551269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } break; 552269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 553269403b032f965ff3847eb982c2f697229dc5a92Svetoslav case PrintJobInfo.STATE_QUEUED: { 554269403b032f965ff3847eb982c2f697229dc5a92Svetoslav sendOnPrintJobQueued(new PrintJobInfo(printJob)); 555269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } break; 556269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 557269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 558269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (shouldPersistPrintJob(printJob)) { 559269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPersistanceManager.writeStateLocked(); 560269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 561269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 562269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!hasActivePrintJobsLocked()) { 563269403b032f965ff3847eb982c2f697229dc5a92Svetoslav notifyOnAllPrintJobsHandled(); 564269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 565704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov 5664bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann notifyPrintJobUpdated(printJob); 567269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 568269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 569269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 570269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return success; 571269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 572269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 573b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann /** 574b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann * Set the progress for a print job. 575b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann * 576b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann * @param printJobId ID of the print job to update 577b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann * @param progress the new progress 578b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann */ 579b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann public void setProgress(@NonNull PrintJobId printJobId, 580b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann @FloatRange(from=0.0, to=1.0) float progress) { 581b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann synchronized (mLock) { 582b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setProgress(progress); 583b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 584b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann mNotificationController.onUpdateNotifications(mPrintJobs); 585b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 586b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 587b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 588d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann /** 589d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * Set the status for a print job. 590d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * 591d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * @param printJobId ID of the print job to update 592d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * @param status the new status 593d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann */ 594d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) { 595d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann synchronized (mLock) { 5964bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 597d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann 5984bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann if (printJob != null) { 5994bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann printJob.setStatus(status); 6004bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann notifyPrintJobUpdated(printJob); 6014bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann } 602d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann } 603d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann } 604d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann 605d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann /** 606d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * Set the status for a print job. 607d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * 608d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * @param printJobId ID of the print job to update 609d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * @param status the new status as a string resource 610d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann * @param appPackageName app package the resource belongs to 611d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann */ 612d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann public void setStatus(@NonNull PrintJobId printJobId, @StringRes int status, 613d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann @Nullable CharSequence appPackageName) { 614d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann synchronized (mLock) { 6154bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 616b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 6174bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann if (printJob != null) { 6184bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann printJob.setStatus(status, appPackageName); 6194bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann notifyPrintJobUpdated(printJob); 6204bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann } 621d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann } 622d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann } 623b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 624269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public boolean hasActivePrintJobsLocked() { 625269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = mPrintJobs.size(); 626269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < printJobCount; i++) { 627269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 628269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (isActiveState(printJob.getState())) { 629269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return true; 630269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 631269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 632269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 633269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 634269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 635269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public boolean hasActivePrintJobsForServiceLocked(ComponentName service) { 636269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = mPrintJobs.size(); 637269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < printJobCount; i++) { 638269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = mPrintJobs.get(i); 63975d28505c8f73a977cc7ae0cc08a60120f7c92b2Svetoslav if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null 640269403b032f965ff3847eb982c2f697229dc5a92Svetoslav && printJob.getPrinterId().getServiceName().equals(service)) { 641269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return true; 642269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 643269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 644269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 645269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 646269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 6472fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav private boolean isObsoleteState(int printJobState) { 648a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav return (isTerminalState(printJobState) 6492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav || printJobState == PrintJobInfo.STATE_QUEUED); 6502fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 6512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav 6529b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov private boolean isScheduledState(int printJobState) { 6539b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov return printJobState == PrintJobInfo.STATE_QUEUED 6549b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov || printJobState == PrintJobInfo.STATE_STARTED 6559b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov || printJobState == PrintJobInfo.STATE_BLOCKED; 6569b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov } 6579b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov 658269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private boolean isActiveState(int printJobState) { 659269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return printJobState == PrintJobInfo.STATE_CREATED 660269403b032f965ff3847eb982c2f697229dc5a92Svetoslav || printJobState == PrintJobInfo.STATE_QUEUED 661d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov || printJobState == PrintJobInfo.STATE_STARTED 662d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov || printJobState == PrintJobInfo.STATE_BLOCKED; 663269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 664269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 665a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav private boolean isTerminalState(int printJobState) { 6662fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav return printJobState == PrintJobInfo.STATE_COMPLETED 6672fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav || printJobState == PrintJobInfo.STATE_CANCELED; 6682fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav } 6692fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav 6702fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav public boolean setPrintJobTag(PrintJobId printJobId, String tag) { 671269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 672269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 673269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printJob != null) { 674269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String printJobTag = printJob.getTag(); 675269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printJobTag == null) { 676269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (tag == null) { 677269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 678269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 679269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } else if (printJobTag.equals(tag)) { 680269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 681269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 682269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setTag(tag); 683269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (shouldPersistPrintJob(printJob)) { 684269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPersistanceManager.writeStateLocked(); 685269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 686269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return true; 687269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 688269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 689269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 690269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 691269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 692a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) { 693a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov synchronized (mLock) { 694a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); 695a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov if (printJob != null) { 696a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov printJob.setCancelling(cancelling); 697a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov if (shouldPersistPrintJob(printJob)) { 698a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov mPersistanceManager.writeStateLocked(); 699a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov } 700a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov mNotificationController.onUpdateNotifications(mPrintJobs); 701a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov 702a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov Message message = mHandlerCaller.obtainMessageO( 703a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, 704a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov printJob); 705a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov mHandlerCaller.executeOrSendMessage(message); 706a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov } 707a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov } 708a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov } 709a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov 710a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav public void updatePrintJobUserConfigurableOptionsNoPersistence(PrintJobInfo printJob) { 711269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 712a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav final int printJobCount = mPrintJobs.size(); 713a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav for (int i = 0; i < printJobCount; i++) { 714a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav PrintJobInfo cachedPrintJob = mPrintJobs.get(i); 715a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav if (cachedPrintJob.getId().equals(printJob.getId())) { 716a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setPrinterId(printJob.getPrinterId()); 717a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setPrinterName(printJob.getPrinterName()); 718a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setCopies(printJob.getCopies()); 719a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo()); 720a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setPages(printJob.getPages()); 721a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setAttributes(printJob.getAttributes()); 722a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions()); 723a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav return; 724a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav } 725269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 726a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav throw new IllegalArgumentException("No print job with id:" + printJob.getId()); 727269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 728269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 729269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 730269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private boolean shouldPersistPrintJob(PrintJobInfo printJob) { 731269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return printJob.getState() >= PrintJobInfo.STATE_QUEUED; 732269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 733269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 734269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void notifyOnAllPrintJobsHandled() { 735269403b032f965ff3847eb982c2f697229dc5a92Svetoslav // This has to run on the tread that is persisting the current state 736269403b032f965ff3847eb982c2f697229dc5a92Svetoslav // since this call may result in the system unbinding from the spooler 737269403b032f965ff3847eb982c2f697229dc5a92Svetoslav // and as a result the spooler process may get killed before the write 738269403b032f965ff3847eb982c2f697229dc5a92Svetoslav // completes. 739269403b032f965ff3847eb982c2f697229dc5a92Svetoslav new AsyncTask<Void, Void, Void>() { 740269403b032f965ff3847eb982c2f697229dc5a92Svetoslav @Override 741269403b032f965ff3847eb982c2f697229dc5a92Svetoslav protected Void doInBackground(Void... params) { 742269403b032f965ff3847eb982c2f697229dc5a92Svetoslav sendOnAllPrintJobsHandled(); 743269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return null; 744269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 745269403b032f965ff3847eb982c2f697229dc5a92Svetoslav }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); 746269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 747269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 748bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann /** 749bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * Handle that a custom icon for a printer was loaded. 750bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * 751bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @param printerId the id of the printer the icon belongs to 752bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @param icon the icon that was loaded 753bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() 754bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann */ 755bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) { 756bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon); 757bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 758bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 759bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann /** 760bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * Get the custom icon for a printer. If the icon is not cached, the icon is 761bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * requested asynchronously. Once it is available the printer is updated. 762bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * 763bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @param printerId the id of the printer the icon should be loaded for 764bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @return the custom icon to be used for the printer or null if the icon is 765bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * not yet available 766bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() 767bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann */ 768bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public Icon getCustomPrinterIcon(PrinterId printerId) { 769bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann return mCustomIconCache.getIcon(printerId); 770bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 771bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 772bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann /** 773bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann * Clear the custom printer icon cache. 774bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann */ 775bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void clearCustomPrinterIconCache() { 776bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann mCustomIconCache.clear(); 777bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 778bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 779269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private final class PersistenceManager { 780269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String PERSIST_FILE_NAME = "print_spooler_state.xml"; 781269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 782269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_SPOOLER = "spooler"; 783269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_JOB = "job"; 784269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 785269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_PRINTER_ID = "printerId"; 786269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_PAGE_RANGE = "pageRange"; 787269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_ATTRIBUTES = "attributes"; 788269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_DOCUMENT_INFO = "documentInfo"; 789269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 790269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_ID = "id"; 791269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_LABEL = "label"; 792773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav private static final String ATTR_LABEL_RES_ID = "labelResId"; 793773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav private static final String ATTR_PACKAGE_NAME = "packageName"; 794269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_STATE = "state"; 795269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_APP_ID = "appId"; 796269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_TAG = "tag"; 797704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov private static final String ATTR_CREATION_TIME = "creationTime"; 798269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_COPIES = "copies"; 799704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov private static final String ATTR_PRINTER_NAME = "printerName"; 800704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov private static final String ATTR_STATE_REASON = "stateReason"; 801b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann private static final String ATTR_STATUS = "status"; 802b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann private static final String ATTR_PROGRESS = "progress"; 803a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov private static final String ATTR_CANCELLING = "cancelling"; 804269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 805b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String TAG_ADVANCED_OPTIONS = "advancedOptions"; 806b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String TAG_ADVANCED_OPTION = "advancedOption"; 807b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String ATTR_KEY = "key"; 808b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String ATTR_TYPE = "type"; 809b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String ATTR_VALUE = "value"; 810b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String TYPE_STRING = "string"; 811b4fda134761c9521a7e127db3806a07a18763b77Svetoslav private static final String TYPE_INT = "int"; 812b4fda134761c9521a7e127db3806a07a18763b77Svetoslav 813269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_MEDIA_SIZE = "mediaSize"; 814269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_RESOLUTION = "resolution"; 815269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String TAG_MARGINS = "margins"; 816269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 817269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_COLOR_MODE = "colorMode"; 818948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav private static final String ATTR_DUPLEX_MODE = "duplexMode"; 819269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 820704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov private static final String ATTR_LOCAL_ID = "localId"; 821269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_SERVICE_NAME = "serviceName"; 822269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 823269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_WIDTH_MILS = "widthMils"; 824269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_HEIGHT_MILS = "heightMils"; 825269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 826269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_HORIZONTAL_DPI = "horizontalDip"; 827269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_VERTICAL_DPI = "verticalDpi"; 828269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 829269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_LEFT_MILS = "leftMils"; 830269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_TOP_MILS = "topMils"; 831269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_RIGHT_MILS = "rightMils"; 832269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_BOTTOM_MILS = "bottomMils"; 833269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 834269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_START = "start"; 835269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_END = "end"; 836269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 837269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_NAME = "name"; 838269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_PAGE_COUNT = "pageCount"; 839269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private static final String ATTR_CONTENT_TYPE = "contentType"; 8407d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov private static final String ATTR_DATA_SIZE = "dataSize"; 841269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 842269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private final AtomicFile mStatePersistFile; 843269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 844269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private boolean mWriteStateScheduled; 845269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 846269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private PersistenceManager() { 847269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mStatePersistFile = new AtomicFile(new File(getFilesDir(), 848269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PERSIST_FILE_NAME)); 849269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 850269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 851269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public void writeStateLocked() { 8524237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov if (!PERSISTENCE_MANAGER_ENABLED) { 853269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return; 854269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 855269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (mWriteStateScheduled) { 856269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return; 857269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 858269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mWriteStateScheduled = true; 859269403b032f965ff3847eb982c2f697229dc5a92Svetoslav new AsyncTask<Void, Void, Void>() { 860269403b032f965ff3847eb982c2f697229dc5a92Svetoslav @Override 861269403b032f965ff3847eb982c2f697229dc5a92Svetoslav protected Void doInBackground(Void... params) { 862269403b032f965ff3847eb982c2f697229dc5a92Svetoslav synchronized (mLock) { 863269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mWriteStateScheduled = false; 864269403b032f965ff3847eb982c2f697229dc5a92Svetoslav doWriteStateLocked(); 865269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 866269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return null; 867269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 868269403b032f965ff3847eb982c2f697229dc5a92Svetoslav }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); 869269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 870269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 871269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void doWriteStateLocked() { 872269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PERSISTENCE) { 873269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.i(LOG_TAG, "[PERSIST START]"); 874269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 875269403b032f965ff3847eb982c2f697229dc5a92Svetoslav FileOutputStream out = null; 876269403b032f965ff3847eb982c2f697229dc5a92Svetoslav try { 877269403b032f965ff3847eb982c2f697229dc5a92Svetoslav out = mStatePersistFile.startWrite(); 878269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 879269403b032f965ff3847eb982c2f697229dc5a92Svetoslav XmlSerializer serializer = new FastXmlSerializer(); 8809e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz serializer.setOutput(out, StandardCharsets.UTF_8.name()); 881269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startDocument(null, true); 882269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_SPOOLER); 883269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 884269403b032f965ff3847eb982c2f697229dc5a92Svetoslav List<PrintJobInfo> printJobs = mPrintJobs; 885269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 886269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int printJobCount = printJobs.size(); 887269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int j = 0; j < printJobCount; j++) { 888269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = printJobs.get(j); 889269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 890885810de69d75979df4299d21fa236490767eae4Svetoslav if (!shouldPersistPrintJob(printJob)) { 891885810de69d75979df4299d21fa236490767eae4Svetoslav continue; 892885810de69d75979df4299d21fa236490767eae4Svetoslav } 893885810de69d75979df4299d21fa236490767eae4Svetoslav 894269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_JOB); 895269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 8962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString()); 897269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString()); 898269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState())); 899269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId())); 900269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String tag = printJob.getTag(); 901269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (tag != null) { 902269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_TAG, tag); 903269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 904704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf( 905704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov printJob.getCreationTime())); 906269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies())); 907704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov String printerName = printJob.getPrinterName(); 908704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov if (!TextUtils.isEmpty(printerName)) { 909704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov serializer.attribute(null, ATTR_PRINTER_NAME, printerName); 910704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov } 911a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov serializer.attribute(null, ATTR_CANCELLING, String.valueOf( 912a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov printJob.isCancelling())); 913269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 914b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann float progress = printJob.getProgress(); 915b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann if (progress != Float.NaN) { 916b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann serializer.attribute(null, ATTR_PROGRESS, String.valueOf(progress)); 917b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 918b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 919d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann CharSequence status = printJob.getStatus(getPackageManager()); 920b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann if (!TextUtils.isEmpty(status)) { 921b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann serializer.attribute(null, ATTR_STATUS, status.toString()); 922b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 923b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 924269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrinterId printerId = printJob.getPrinterId(); 925269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (printerId != null) { 926269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_PRINTER_ID); 927269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId()); 928269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName() 929269403b032f965ff3847eb982c2f697229dc5a92Svetoslav .flattenToString()); 930269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_PRINTER_ID); 931269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 932269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 933269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PageRange[] pages = printJob.getPages(); 934269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (pages != null) { 935269403b032f965ff3847eb982c2f697229dc5a92Svetoslav for (int i = 0; i < pages.length; i++) { 936269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_PAGE_RANGE); 937269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_START, String.valueOf( 938269403b032f965ff3847eb982c2f697229dc5a92Svetoslav pages[i].getStart())); 939269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_END, String.valueOf( 940269403b032f965ff3847eb982c2f697229dc5a92Svetoslav pages[i].getEnd())); 941269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_PAGE_RANGE); 942269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 943269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 944269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 945269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintAttributes attributes = printJob.getAttributes(); 946269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (attributes != null) { 947269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_ATTRIBUTES); 948269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 949269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int colorMode = attributes.getColorMode(); 950269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_COLOR_MODE, 951269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String.valueOf(colorMode)); 952269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 953948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav final int duplexMode = attributes.getDuplexMode(); 954948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav serializer.attribute(null, ATTR_DUPLEX_MODE, 955948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav String.valueOf(duplexMode)); 956948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav 957269403b032f965ff3847eb982c2f697229dc5a92Svetoslav MediaSize mediaSize = attributes.getMediaSize(); 958269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (mediaSize != null) { 959269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_MEDIA_SIZE); 960269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_ID, mediaSize.getId()); 961269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf( 962269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mediaSize.getWidthMils())); 963269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf( 964269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mediaSize.getHeightMils())); 965a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav // We prefer to store only the package name and 966a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav // resource id and fallback to the label. 967a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav if (!TextUtils.isEmpty(mediaSize.mPackageName) 968773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav && mediaSize.mLabelResId > 0) { 969773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav serializer.attribute(null, ATTR_PACKAGE_NAME, 970773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav mediaSize.mPackageName); 971773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav serializer.attribute(null, ATTR_LABEL_RES_ID, 972773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav String.valueOf(mediaSize.mLabelResId)); 973773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav } else { 974773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav serializer.attribute(null, ATTR_LABEL, 975773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav mediaSize.getLabel(getPackageManager())); 976773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav } 977269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_MEDIA_SIZE); 978269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 979269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 980269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Resolution resolution = attributes.getResolution(); 981269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (resolution != null) { 982269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_RESOLUTION); 983269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_ID, resolution.getId()); 984269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf( 985269403b032f965ff3847eb982c2f697229dc5a92Svetoslav resolution.getHorizontalDpi())); 986269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf( 987269403b032f965ff3847eb982c2f697229dc5a92Svetoslav resolution.getVerticalDpi())); 988c6066799ad130140159230d14451b429eb828755Svetoslav serializer.attribute(null, ATTR_LABEL, 989651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav resolution.getLabel()); 990269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_RESOLUTION); 991269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 992269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 993651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav Margins margins = attributes.getMinMargins(); 994269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (margins != null) { 995269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_MARGINS); 996269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf( 997269403b032f965ff3847eb982c2f697229dc5a92Svetoslav margins.getLeftMils())); 998269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_TOP_MILS, String.valueOf( 999269403b032f965ff3847eb982c2f697229dc5a92Svetoslav margins.getTopMils())); 1000269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf( 1001269403b032f965ff3847eb982c2f697229dc5a92Svetoslav margins.getRightMils())); 1002269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf( 1003269403b032f965ff3847eb982c2f697229dc5a92Svetoslav margins.getBottomMils())); 1004269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_MARGINS); 1005269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1006269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1007269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_ATTRIBUTES); 1008269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1009269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1010269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintDocumentInfo documentInfo = printJob.getDocumentInfo(); 1011269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (documentInfo != null) { 1012269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.startTag(null, TAG_DOCUMENT_INFO); 1013269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_NAME, documentInfo.getName()); 1014269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf( 1015269403b032f965ff3847eb982c2f697229dc5a92Svetoslav documentInfo.getContentType())); 1016269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf( 1017269403b032f965ff3847eb982c2f697229dc5a92Svetoslav documentInfo.getPageCount())); 10187d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov serializer.attribute(null, ATTR_DATA_SIZE, String.valueOf( 10197d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov documentInfo.getDataSize())); 1020269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_DOCUMENT_INFO); 1021269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1022269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1023b4fda134761c9521a7e127db3806a07a18763b77Svetoslav Bundle advancedOptions = printJob.getAdvancedOptions(); 1024b4fda134761c9521a7e127db3806a07a18763b77Svetoslav if (advancedOptions != null) { 1025b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.startTag(null, TAG_ADVANCED_OPTIONS); 1026b4fda134761c9521a7e127db3806a07a18763b77Svetoslav for (String key : advancedOptions.keySet()) { 1027b4fda134761c9521a7e127db3806a07a18763b77Svetoslav Object value = advancedOptions.get(key); 1028b4fda134761c9521a7e127db3806a07a18763b77Svetoslav if (value instanceof String) { 1029b4fda134761c9521a7e127db3806a07a18763b77Svetoslav String stringValue = (String) value; 1030b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.startTag(null, TAG_ADVANCED_OPTION); 1031b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_KEY, key); 1032b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_TYPE, TYPE_STRING); 1033b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_VALUE, stringValue); 1034b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.endTag(null, TAG_ADVANCED_OPTION); 1035b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } else if (value instanceof Integer) { 1036b4fda134761c9521a7e127db3806a07a18763b77Svetoslav String intValue = Integer.toString((Integer) value); 1037b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.startTag(null, TAG_ADVANCED_OPTION); 1038b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_KEY, key); 1039b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_TYPE, TYPE_INT); 1040b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.attribute(null, ATTR_VALUE, intValue); 1041b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.endTag(null, TAG_ADVANCED_OPTION); 1042b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1043b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1044b4fda134761c9521a7e127db3806a07a18763b77Svetoslav serializer.endTag(null, TAG_ADVANCED_OPTIONS); 1045b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1046b4fda134761c9521a7e127db3806a07a18763b77Svetoslav 1047269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_JOB); 1048269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1049269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PERSISTENCE) { 1050269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.i(LOG_TAG, "[PERSISTED] " + printJob); 1051269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1052269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1053269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1054269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endTag(null, TAG_SPOOLER); 1055269403b032f965ff3847eb982c2f697229dc5a92Svetoslav serializer.endDocument(); 1056269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mStatePersistFile.finishWrite(out); 1057269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PERSISTENCE) { 1058269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.i(LOG_TAG, "[PERSIST END]"); 1059269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1060269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (IOException e) { 1061269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e); 1062269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mStatePersistFile.failWrite(out); 1063269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } finally { 1064269403b032f965ff3847eb982c2f697229dc5a92Svetoslav IoUtils.closeQuietly(out); 1065269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1066269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1067269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1068269403b032f965ff3847eb982c2f697229dc5a92Svetoslav public void readStateLocked() { 10694237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov if (!PERSISTENCE_MANAGER_ENABLED) { 1070269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return; 1071269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1072269403b032f965ff3847eb982c2f697229dc5a92Svetoslav FileInputStream in = null; 1073269403b032f965ff3847eb982c2f697229dc5a92Svetoslav try { 1074269403b032f965ff3847eb982c2f697229dc5a92Svetoslav in = mStatePersistFile.openRead(); 1075269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (FileNotFoundException e) { 107613460a6cba25b99c405d00bb40939958df332f3fJoe Onorato if (DEBUG_PERSISTENCE) { 107713460a6cba25b99c405d00bb40939958df332f3fJoe Onorato Log.d(LOG_TAG, "No existing print spooler state."); 107813460a6cba25b99c405d00bb40939958df332f3fJoe Onorato } 1079269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return; 1080269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1081269403b032f965ff3847eb982c2f697229dc5a92Svetoslav try { 1082269403b032f965ff3847eb982c2f697229dc5a92Svetoslav XmlPullParser parser = Xml.newPullParser(); 10839e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz parser.setInput(in, StandardCharsets.UTF_8.name()); 1084269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parseState(parser); 1085269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (IllegalStateException ise) { 1086269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", ise); 1087269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (NullPointerException npe) { 1088269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", npe); 1089269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (NumberFormatException nfe) { 1090269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", nfe); 1091269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (XmlPullParserException xppe) { 1092269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", xppe); 1093269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (IOException ioe) { 1094269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", ioe); 1095269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } catch (IndexOutOfBoundsException iobe) { 1096269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Slog.w(LOG_TAG, "Failed parsing ", iobe); 1097269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } finally { 1098269403b032f965ff3847eb982c2f697229dc5a92Svetoslav IoUtils.closeQuietly(in); 1099269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void parseState(XmlPullParser parser) 1103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav throws IOException, XmlPullParserException { 1104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER); 1107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav while (parsePrintJob(parser)) { 1110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1111269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER); 1115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1116269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private boolean parsePrintJob(XmlPullParser parser) 1118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav throws IOException, XmlPullParserException { 1119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) { 1121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 1122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintJobInfo printJob = new PrintJobInfo(); 1125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 11262fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav PrintJobId printJobId = PrintJobId.unflattenFromString( 11272fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav parser.getAttributeValue(null, ATTR_ID)); 1128269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setId(printJobId); 1129269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String label = parser.getAttributeValue(null, ATTR_LABEL); 1130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setLabel(label); 1131269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE)); 1132269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setState(state); 1133269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID)); 1134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setAppId(appId); 1135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String tag = parser.getAttributeValue(null, ATTR_TAG); 1136269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setTag(tag); 1137704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME); 1138704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov printJob.setCreationTime(Long.parseLong(creationTime)); 1139269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String copies = parser.getAttributeValue(null, ATTR_COPIES); 1140269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setCopies(Integer.parseInt(copies)); 1141704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME); 1142704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov printJob.setPrinterName(printerName); 1143b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1144b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann String progressString = parser.getAttributeValue(null, ATTR_PROGRESS); 1145b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann if (progressString != null) { 1146b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann float progress = Float.parseFloat(progressString); 1147b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1148a958fc336b277cf2838ccd50ef3d3484644b100aPhilip P. Moltmann if (progress != -1) { 1149b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann printJob.setProgress(progress); 1150b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 1151b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 1152b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1153b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann CharSequence status = parser.getAttributeValue(null, ATTR_STATUS); 1154b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann printJob.setStatus(status); 1155b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1156b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann // stateReason is deprecated, but might be used by old print jobs 1157704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON); 1158b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann if (stateReason != null) { 1159b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann printJob.setStatus(stateReason); 1160b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 1161b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1162a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING); 1163a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov printJob.setCancelling(!TextUtils.isEmpty(cancelling) 1164a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov ? Boolean.parseBoolean(cancelling) : false); 1165269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1166269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1167269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1168269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1169269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) { 1170269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID); 1171269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue( 1172269403b032f965ff3847eb982c2f697229dc5a92Svetoslav null, ATTR_SERVICE_NAME)); 1173269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setPrinterId(new PrinterId(service, localId)); 1174269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1175269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1176269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); 1177269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1178269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1179269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1180269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1181269403b032f965ff3847eb982c2f697229dc5a92Svetoslav List<PageRange> pageRanges = null; 1182269403b032f965ff3847eb982c2f697229dc5a92Svetoslav while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) { 1183269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START)); 1184269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END)); 1185269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PageRange pageRange = new PageRange(start, end); 1186269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (pageRanges == null) { 1187269403b032f965ff3847eb982c2f697229dc5a92Svetoslav pageRanges = new ArrayList<PageRange>(); 1188269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1189269403b032f965ff3847eb982c2f697229dc5a92Svetoslav pageRanges.add(pageRange); 1190269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE); 1193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1194b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (pageRanges != null) { 1197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PageRange[] pageRangesArray = new PageRange[pageRanges.size()]; 1198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav pageRanges.toArray(pageRangesArray); 1199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setPages(pageRangesArray); 1200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1201269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1202269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1203269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) { 1204269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1205269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintAttributes.Builder builder = new PrintAttributes.Builder(); 1206269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1207269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE); 1208269403b032f965ff3847eb982c2f697229dc5a92Svetoslav builder.setColorMode(Integer.parseInt(colorMode)); 1209269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1210948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE); 1211948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav // Duplex mode was added later, so null check is needed. 1212948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav if (duplexMode != null) { 1213948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav builder.setDuplexMode(Integer.parseInt(duplexMode)); 1214948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav } 1215948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav 1216269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1217269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1218269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1219269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) { 1220269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String id = parser.getAttributeValue(null, ATTR_ID); 1221269403b032f965ff3847eb982c2f697229dc5a92Svetoslav label = parser.getAttributeValue(null, ATTR_LABEL); 1222269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int widthMils = Integer.parseInt(parser.getAttributeValue(null, 1223269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_WIDTH_MILS)); 1224269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int heightMils = Integer.parseInt(parser.getAttributeValue(null, 1225269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_HEIGHT_MILS)); 1226773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); 1227b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID); 1228b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav final int labelResId = (labelResIdString != null) 1229b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav ? Integer.parseInt(labelResIdString) : 0; 1230773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav label = parser.getAttributeValue(null, ATTR_LABEL); 1231b4fda134761c9521a7e127db3806a07a18763b77Svetoslav MediaSize mediaSize = new MediaSize(id, label, packageName, 1232b4fda134761c9521a7e127db3806a07a18763b77Svetoslav widthMils, heightMils, labelResId); 1233269403b032f965ff3847eb982c2f697229dc5a92Svetoslav builder.setMediaSize(mediaSize); 1234269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1235269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1236269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE); 1237269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1238269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1239269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1240269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1241269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) { 1242269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String id = parser.getAttributeValue(null, ATTR_ID); 1243269403b032f965ff3847eb982c2f697229dc5a92Svetoslav label = parser.getAttributeValue(null, ATTR_LABEL); 1244269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null, 1245269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_HORIZONTAL_DPI)); 1246269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null, 1247269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_VERTICAL_DPI)); 1248c6066799ad130140159230d14451b429eb828755Svetoslav Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi); 1249269403b032f965ff3847eb982c2f697229dc5a92Svetoslav builder.setResolution(resolution); 1250269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1251269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1252269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION); 1253269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1254269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1255269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1256269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1257269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) { 1258269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int leftMils = Integer.parseInt(parser.getAttributeValue(null, 1259269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_LEFT_MILS)); 1260269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int topMils = Integer.parseInt(parser.getAttributeValue(null, 1261269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_TOP_MILS)); 1262269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int rightMils = Integer.parseInt(parser.getAttributeValue(null, 1263269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_RIGHT_MILS)); 1264269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int bottomMils = Integer.parseInt(parser.getAttributeValue(null, 1265269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_BOTTOM_MILS)); 1266269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils); 1267651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav builder.setMinMargins(margins); 1268269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1269269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1270269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_MARGINS); 1271269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1272269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1273269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1274651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav printJob.setAttributes(builder.build()); 1275269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1276269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1277269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES); 1278269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1279269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1280269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1281269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) { 1283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav String name = parser.getAttributeValue(null, ATTR_NAME); 1284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int pageCount = Integer.parseInt(parser.getAttributeValue(null, 1285269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_PAGE_COUNT)); 1286269403b032f965ff3847eb982c2f697229dc5a92Svetoslav final int contentType = Integer.parseInt(parser.getAttributeValue(null, 1287269403b032f965ff3847eb982c2f697229dc5a92Svetoslav ATTR_CONTENT_TYPE)); 12887d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov final int dataSize = Integer.parseInt(parser.getAttributeValue(null, 12897d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov ATTR_DATA_SIZE)); 1290269403b032f965ff3847eb982c2f697229dc5a92Svetoslav PrintDocumentInfo info = new PrintDocumentInfo.Builder(name) 1291269403b032f965ff3847eb982c2f697229dc5a92Svetoslav .setPageCount(pageCount) 1292651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav .setContentType(contentType).build(); 1293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav printJob.setDocumentInfo(info); 12947d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov info.setDataSize(dataSize); 1295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1296269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1297269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO); 1298269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1299269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1300269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1301b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1302b4fda134761c9521a7e127db3806a07a18763b77Svetoslav if (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTIONS)) { 1303b4fda134761c9521a7e127db3806a07a18763b77Svetoslav parser.next(); 1304b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1305b4fda134761c9521a7e127db3806a07a18763b77Svetoslav Bundle advancedOptions = new Bundle(); 1306b4fda134761c9521a7e127db3806a07a18763b77Svetoslav while (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTION)) { 1307b4fda134761c9521a7e127db3806a07a18763b77Svetoslav String key = parser.getAttributeValue(null, ATTR_KEY); 1308b4fda134761c9521a7e127db3806a07a18763b77Svetoslav String value = parser.getAttributeValue(null, ATTR_VALUE); 1309b4fda134761c9521a7e127db3806a07a18763b77Svetoslav String type = parser.getAttributeValue(null, ATTR_TYPE); 1310b4fda134761c9521a7e127db3806a07a18763b77Svetoslav if (TYPE_STRING.equals(type)) { 1311b4fda134761c9521a7e127db3806a07a18763b77Svetoslav advancedOptions.putString(key, value); 1312b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } else if (TYPE_INT.equals(type)) { 1313b4fda134761c9521a7e127db3806a07a18763b77Svetoslav advancedOptions.putInt(key, Integer.valueOf(value)); 1314b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1315b4fda134761c9521a7e127db3806a07a18763b77Svetoslav parser.next(); 1316b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1317b4fda134761c9521a7e127db3806a07a18763b77Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTION); 1318b4fda134761c9521a7e127db3806a07a18763b77Svetoslav parser.next(); 1319b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1320b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1321b4fda134761c9521a7e127db3806a07a18763b77Svetoslav printJob.setAdvancedOptions(advancedOptions); 1322b4fda134761c9521a7e127db3806a07a18763b77Svetoslav skipEmptyTextTags(parser); 1323b4fda134761c9521a7e127db3806a07a18763b77Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTIONS); 1324b4fda134761c9521a7e127db3806a07a18763b77Svetoslav parser.next(); 1325b4fda134761c9521a7e127db3806a07a18763b77Svetoslav } 1326b4fda134761c9521a7e127db3806a07a18763b77Svetoslav 1327269403b032f965ff3847eb982c2f697229dc5a92Svetoslav mPrintJobs.add(printJob); 1328269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1329269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (DEBUG_PERSISTENCE) { 1330269403b032f965ff3847eb982c2f697229dc5a92Svetoslav Log.i(LOG_TAG, "[RESTORED] " + printJob); 1331269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1332269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1333269403b032f965ff3847eb982c2f697229dc5a92Svetoslav skipEmptyTextTags(parser); 1334269403b032f965ff3847eb982c2f697229dc5a92Svetoslav expect(parser, XmlPullParser.END_TAG, TAG_JOB); 1335269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1336269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return true; 1337269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1338269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1339269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void expect(XmlPullParser parser, int type, String tag) 1340c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann throws XmlPullParserException { 1341269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!accept(parser, type, tag)) { 1342269403b032f965ff3847eb982c2f697229dc5a92Svetoslav throw new XmlPullParserException("Exepected event: " + type 1343269403b032f965ff3847eb982c2f697229dc5a92Svetoslav + " and tag: " + tag + " but got event: " + parser.getEventType() 1344269403b032f965ff3847eb982c2f697229dc5a92Svetoslav + " and tag:" + parser.getName()); 1345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1348269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private void skipEmptyTextTags(XmlPullParser parser) 1349269403b032f965ff3847eb982c2f697229dc5a92Svetoslav throws IOException, XmlPullParserException { 1350269403b032f965ff3847eb982c2f697229dc5a92Svetoslav while (accept(parser, XmlPullParser.TEXT, null) 1351269403b032f965ff3847eb982c2f697229dc5a92Svetoslav && "\n".equals(parser.getText())) { 1352269403b032f965ff3847eb982c2f697229dc5a92Svetoslav parser.next(); 1353269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1354269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1355269403b032f965ff3847eb982c2f697229dc5a92Svetoslav 1356269403b032f965ff3847eb982c2f697229dc5a92Svetoslav private boolean accept(XmlPullParser parser, int type, String tag) 1357c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann throws XmlPullParserException { 1358269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (parser.getEventType() != type) { 1359269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 1360269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1361269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (tag != null) { 1362269403b032f965ff3847eb982c2f697229dc5a92Svetoslav if (!tag.equals(parser.getName())) { 1363269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 1364269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1365269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } else if (parser.getName() != null) { 1366269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return false; 1367269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1368269403b032f965ff3847eb982c2f697229dc5a92Svetoslav return true; 1369269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 1370269403b032f965ff3847eb982c2f697229dc5a92Svetoslav } 13717bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 1372a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav public final class PrintSpooler extends IPrintSpooler.Stub { 13737bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 13747bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void getPrintJobInfos(IPrintSpoolerCallbacks callback, 13757bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav ComponentName componentName, int state, int appId, int sequence) 13767bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav throws RemoteException { 13777bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav List<PrintJobInfo> printJobs = null; 13787bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav try { 13797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav printJobs = PrintSpoolerService.this.getPrintJobInfos( 13807bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav componentName, state, appId); 13817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } finally { 13827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav callback.onGetPrintJobInfosResult(printJobs, sequence); 13837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 13847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 13857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 13867bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 13877bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback, 13887bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav int appId, int sequence) throws RemoteException { 13897bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintJobInfo printJob = null; 13907bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav try { 13917bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId); 13927bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } finally { 13937bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav callback.onGetPrintJobInfoResult(printJob, sequence); 13947bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 13957bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 13967bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 13977bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 13987bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void createPrintJob(PrintJobInfo printJob) { 13997bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintSpoolerService.this.createPrintJob(printJob); 14007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14027bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14037bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void setPrintJobState(PrintJobId printJobId, int state, String error, 14047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { 14057bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav boolean success = false; 14067bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav try { 14077bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav success = PrintSpoolerService.this.setPrintJobState( 14087bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav printJobId, state, error); 14097bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } finally { 14107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav callback.onSetPrintJobStateResult(success, sequece); 14117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void setPrintJobTag(PrintJobId printJobId, String tag, 14167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { 14177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav boolean success = false; 14187bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav try { 14197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag); 14207bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } finally { 14217bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav callback.onSetPrintJobTagResult(success, sequece); 14227bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14247bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14257bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14267bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) { 14277bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintSpoolerService.this.writePrintJobData(fd, printJobId); 14287bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14307bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14317bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void setClient(IPrintSpoolerClient client) { 14327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav Message message = mHandlerCaller.obtainMessageO( 14337bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav HandlerCallerCallback.MSG_SET_CLIENT, client); 14347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav mHandlerCaller.executeOrSendMessage(message); 14357bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14367bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14377bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void removeObsoletePrintJobs() { 14397bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintSpoolerService.this.removeObsoletePrintJobs(); 14407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14437bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 14447bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintSpoolerService.this.dump(fd, writer, args); 14457bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14467bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 14477bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav @Override 14487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) { 14497bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling); 14507bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 14517bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav 1452853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann @Override 14538141bdfa56f13c3946bed12ba7801e492ec25c11Philip P. Moltmann public void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) { 1454853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann (new ApprovedPrintServices(PrintSpoolerService.this)) 14558141bdfa56f13c3946bed12ba7801e492ec25c11Philip P. Moltmann .pruneApprovedServices(servicesToKeep); 1456853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann } 1457853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann 1458b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann @Override 1459b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann public void setProgress(@NonNull PrintJobId printJobId, 1460b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann @FloatRange(from=0.0, to=1.0) float progress) throws RemoteException { 1461b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann PrintSpoolerService.this.setProgress(printJobId, progress); 1462b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 1463b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1464b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann @Override 1465b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann public void setStatus(@NonNull PrintJobId printJobId, 1466b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann @Nullable CharSequence status) throws RemoteException { 1467b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann PrintSpoolerService.this.setStatus(printJobId, status); 1468b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann } 1469b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann 1470d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann @Override 1471d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann public void setStatusRes(@NonNull PrintJobId printJobId, @StringRes int status, 1472d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann @NonNull CharSequence appPackageName) throws RemoteException { 1473d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann PrintSpoolerService.this.setStatus(printJobId, status, appPackageName); 1474d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann } 1475d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann 1476d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann 14777bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav public PrintSpoolerService getService() { 14787bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav return PrintSpoolerService.this; 14797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 1480bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 1481bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann @Override 1482bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon, 1483bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann IPrintSpoolerCallbacks callbacks, int sequence) 1484bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann throws RemoteException { 1485bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann try { 1486bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann PrintSpoolerService.this.onCustomPrinterIconLoaded(printerId, icon); 1487bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } finally { 1488bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann callbacks.onCustomPrinterIconCached(sequence); 1489bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1490bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1491bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 1492bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann @Override 1493bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void getCustomPrinterIcon(PrinterId printerId, IPrintSpoolerCallbacks callbacks, 1494bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann int sequence) throws RemoteException { 1495bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann Icon icon = null; 1496bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann try { 1497bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann icon = PrintSpoolerService.this.getCustomPrinterIcon(printerId); 1498bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } finally { 1499bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann callbacks.onGetCustomPrinterIconResult(icon, sequence); 1500bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1501bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1502bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 1503bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann @Override 1504bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann public void clearCustomPrinterIconCache(IPrintSpoolerCallbacks callbacks, 1505bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann int sequence) throws RemoteException { 1506bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann try { 1507bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann PrintSpoolerService.this.clearCustomPrinterIconCache(); 1508bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } finally { 1509bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann callbacks.customPrinterIconCacheCleared(sequence); 1510bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1511bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann } 1512bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann 15137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav } 15144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov} 1515