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
922e3012624b703a653fed44d4dc1b8904406c0d99Philip P. Moltmann    private static final String PRINT_JOB_STATE_HISTO = "print_job_state";
932e3012624b703a653fed44d4dc1b8904406c0d99Philip P. Moltmann
94835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000;
95835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
96dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private static final String PRINT_JOB_FILE_PREFIX = "print_job_";
97dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
98269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final String PRINT_FILE_EXTENSION = "pdf";
99269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final Object sLock = new Object();
101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final Object mLock = new Object();
103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
104a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    private final List<PrintJobInfo> mPrintJobs = new ArrayList<>();
105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static PrintSpoolerService sInstance;
107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
108835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private IPrintSpoolerClient mClient;
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private HandlerCaller mHandlerCaller;
111269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private PersistenceManager mPersistanceManager;
113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private NotificationController mNotificationController;
115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
116bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    /** Cache for custom printer icons loaded from the print service */
117bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    private CustomPrinterIconCache mCustomIconCache;
118bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public static PrintSpoolerService peekInstance() {
120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return sInstance;
122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
1244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public void onCreate() {
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        super.onCreate();
128269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller = new HandlerCaller(this, getMainLooper(),
129269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                new HandlerCallerCallback(), false);
130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
131269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPersistanceManager = new PersistenceManager();
132269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mNotificationController = new NotificationController(PrintSpoolerService.this);
133bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        mCustomIconCache = new CustomPrinterIconCache(getCacheDir());
134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
136269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPersistanceManager.readStateLocked();
137269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            handleReadPrintJobsLocked();
138269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
139269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
140269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
141269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            sInstance = this;
142269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
146bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    public void onDestroy() {
147bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        super.onDestroy();
148bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    }
149bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
150bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    @Override
1514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public IBinder onBind(Intent intent) {
1527bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        return new PrintSpooler();
1534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
155dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    @Override
156dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
157853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        String prefix = (args.length > 0) ? args[0] : "";
158853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        String tab = "  ";
159dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
160853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        synchronized (mLock) {
161dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print jobs:").println();
162dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int printJobCount = mPrintJobs.size();
163dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < printJobCount; i++) {
164dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                PrintJobInfo printJob = mPrintJobs.get(i);
165dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.append(prefix).append(tab).append(printJob.toString());
166dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.println();
167dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
168dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
169dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print job files:").println();
170dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            File[] files = getFilesDir().listFiles();
171dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (files != null) {
172dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int fileCount = files.length;
173dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < fileCount; i++) {
174dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    File file = files[i];
175dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
176dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        pw.append(prefix).append(tab).append(file.getName()).println();
177dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
178dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
179dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
180dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
181853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann
182853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        pw.append(prefix).append("approved print services:").println();
183853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        Set<String> approvedPrintServices = (new ApprovedPrintServices(this)).getApprovedServices();
184853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        if (approvedPrintServices != null) {
185853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann            for (String approvedService : approvedPrintServices) {
186853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann                pw.append(prefix).append(tab).append(approvedService).println();
187853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann            }
188853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        }
189dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    }
190dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnPrintJobQueued(PrintJobInfo printJob) {
192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsForServiceHandled(ComponentName service) {
198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service);
200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
201269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
202269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
203269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsHandled() {
204269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessage(
205269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED);
206269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
207269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
208269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
209269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class HandlerCallerCallback implements HandlerCaller.Callback {
210704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public static final int MSG_SET_CLIENT = 1;
2117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_QUEUED = 2;
2127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 3;
2137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 4;
2147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 5;
2157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 6;
2164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
218269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void executeMessage(Message message) {
219835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            switch (message.what) {
220835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_SET_CLIENT: {
221269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
222269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mClient = (IPrintSpoolerClient) message.obj;
223269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mClient != null) {
224269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            Message msg = mHandlerCaller.obtainMessage(
225269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED);
226269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            mHandlerCaller.sendMessageDelayed(msg,
227269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    CHECK_ALL_PRINTJOBS_HANDLED_DELAY);
228269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
229835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
230835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
231835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
232835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_PRINT_JOB_QUEUED: {
233835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
234835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
235835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
236835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onPrintJobQueued(printJob);
237835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
238835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
239835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
240835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
241835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
242835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
243835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: {
244835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    ComponentName service = (ComponentName) message.obj;
245835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
246835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
247835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsForServiceHandled(service);
248835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
249835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print jobs per service"
250835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                    + " handled.", re);
251835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
252835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
253835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
254835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
255835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
256835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
257835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
258835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsHandled();
259835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
260835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
261835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
262835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
263835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
264835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
265835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
266269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    checkAllPrintJobsHandled();
267269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
268704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
269704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                case MSG_ON_PRINT_JOB_STATE_CHANGED: {
270704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (mClient != null) {
271dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        PrintJobInfo printJob = (PrintJobInfo) message.obj;
272704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        try {
273dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            mClient.onPrintJobStateChanged(printJob);
274704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        } catch (RemoteException re) {
275704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for print job state change.", re);
276704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        }
277704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
278704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                } break;
2794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
2804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName,
284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            int state, int appId) {
285269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        List<PrintJobInfo> foundPrintJobs = null;
286269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
287269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
288269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
289269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
290269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrinterId printerId = printJob.getPrinterId();
291269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameComponent = (componentName == null
292269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (printerId != null
293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && componentName.equals(printerId.getServiceName())));
294269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameAppId = appId == PrintManager.APP_ID_ANY
295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || printJob.getAppId() == appId;
296269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameState = (state == printJob.getState())
297269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY)
298269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
299d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                            && isStateVisibleToUser(printJob.getState()))
300d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_ACTIVE
3019b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isActiveState(printJob.getState()))
3029b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_SCHEDULED
3039b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isScheduledState(printJob.getState()));
304269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (sameComponent && sameAppId && sameState) {
305269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (foundPrintJobs == null) {
306a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                        foundPrintJobs = new ArrayList<>();
307269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
308269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    foundPrintJobs.add(printJob);
309269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
310269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
311269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
312269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return foundPrintJobs;
313269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
314269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
315d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private boolean isStateVisibleToUser(int state) {
316d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
3172fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
3182fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_BLOCKED));
319d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
320d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
3212fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
322269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
323269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
324269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
325269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
3262fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (printJob.getId().equals(printJobId)
327269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && (appId == PrintManager.APP_ID_ANY
328269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || appId == printJob.getAppId())) {
329269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return printJob;
330269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
331269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
332269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return null;
333269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
334269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
335269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3362fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void createPrintJob(PrintJobInfo printJob) {
337269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
338269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            addPrintJobLocked(printJob);
339dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
3407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
3417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
3427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
3437bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    printJob);
3447bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
348269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void handleReadPrintJobsLocked() {
349dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Make a map with the files for a print job since we may have
350dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // to delete some. One example of getting orphan files if the
351dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // spooler crashes while constructing a print job. We do not
352dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // persist partially populated print jobs under construction to
353dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // avoid special handling for various attributes missing.
354dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        ArrayMap<PrintJobId, File> fileForJobMap = null;
355dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        File[] files = getFilesDir().listFiles();
356dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (files != null) {
357dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int fileCount = files.length;
358dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < fileCount; i++) {
359dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = files[i];
360dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
361dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (fileForJobMap == null) {
362dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        fileForJobMap = new ArrayMap<PrintJobId, File>();
363dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
3642b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                    String printJobIdString = file.getName().substring(
3652b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            PRINT_JOB_FILE_PREFIX.length(),
3662b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            file.getName().indexOf('.'));
367dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    PrintJobId printJobId = PrintJobId.unflattenFromString(
368dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            printJobIdString);
369dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    fileForJobMap.put(printJobId, file);
370dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
371dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
372dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
373dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
374269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
375269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
376269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
377269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
378dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            // We want to have only the orphan files at the end.
379dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (fileForJobMap != null) {
380dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                fileForJobMap.remove(printJob.getId());
381dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
382dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
383269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            switch (printJob.getState()) {
384269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case PrintJobInfo.STATE_QUEUED:
385d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_STARTED:
386d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_BLOCKED: {
387d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // We have a print job that was queued or started or blocked in
388d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // the past but the device battery died or a crash occurred. In
389d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // this case we assume the print job failed and let the user
390d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // decide whether to restart the job or just cancel it.
391269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
392269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            getString(R.string.no_connection_to_printer));
3932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                } break;
394269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
395269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
396dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
397a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        if (!mPrintJobs.isEmpty()) {
398a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            // Update the notification.
399a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            mNotificationController.onUpdateNotifications(mPrintJobs);
400a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
401a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
402dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Delete the orphan files.
403dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (fileForJobMap != null) {
404dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int orphanFileCount = fileForJobMap.size();
405dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < orphanFileCount; i++) {
406dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = fileForJobMap.valueAt(i);
407dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                file.delete();
408dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
409dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
410269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
411269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
412269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public void checkAllPrintJobsHandled() {
413269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
414269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!hasActivePrintJobsLocked()) {
415269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                notifyOnAllPrintJobsHandled();
416269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
417269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
418269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
419269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4202fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
421269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final PrintJobInfo printJob;
422269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
423269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
424269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
425269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
426269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
427269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
428269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileInputStream in = null;
429269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileOutputStream out = null;
430269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                try {
431269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printJob != null) {
432a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                        File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
433269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        in = new FileInputStream(file);
434269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out = new FileOutputStream(fd.getFileDescriptor());
435269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
436269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final byte[] buffer = new byte[8192];
437269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    while (true) {
438269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int readByteCount = in.read(buffer);
439269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (readByteCount < 0) {
440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            return null;
441269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
442269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out.write(buffer, 0, readByteCount);
443269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
444269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (FileNotFoundException fnfe) {
445269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", fnfe);
446269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (IOException ioe) {
447269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", ioe);
448269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } finally {
449269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(in);
450269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(out);
451269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(fd);
452269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
453269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[END WRITE]");
454269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
455269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
456269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
457269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
458269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
459a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public static File generateFileForPrintJob(Context context, PrintJobId printJobId) {
460a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        return new File(context.getFilesDir(), PRINT_JOB_FILE_PREFIX
4612fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
462269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
463269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
464269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void addPrintJobLocked(PrintJobInfo printJob) {
465269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPrintJobs.add(printJob);
466269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (DEBUG_PRINT_JOB_LIFECYCLE) {
467269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            Slog.i(LOG_TAG, "[ADD] " + printJob);
468269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
469269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
470269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4712fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removeObsoletePrintJobs() {
4722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        synchronized (mLock) {
473885810de69d75979df4299d21fa236490767eae4Svetoslav            boolean persistState = false;
4742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            final int printJobCount = mPrintJobs.size();
4752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            for (int i = printJobCount - 1; i >= 0; i--) {
4762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
4772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (isObsoleteState(printJob.getState())) {
4782fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    mPrintJobs.remove(i);
4792fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    if (DEBUG_PRINT_JOB_LIFECYCLE) {
4802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
4812fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    }
4822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    removePrintJobFileLocked(printJob.getId());
483885810de69d75979df4299d21fa236490767eae4Svetoslav                    persistState = true;
4842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                }
4852fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
486885810de69d75979df4299d21fa236490767eae4Svetoslav            if (persistState) {
487885810de69d75979df4299d21fa236490767eae4Svetoslav                mPersistanceManager.writeStateLocked();
488885810de69d75979df4299d21fa236490767eae4Svetoslav            }
4892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
4902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
4912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
4922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removePrintJobFileLocked(PrintJobId printJobId) {
493a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
4942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (file.exists()) {
4952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            file.delete();
496269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PRINT_JOB_LIFECYCLE) {
497dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
498269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
499269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
500269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
501269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
5024bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann    /**
5034bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann     * Notify all interested parties that a print job has been updated.
5044bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann     *
5054bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann     * @param printJob The updated print job.
5064bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann     */
5074bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann    private void notifyPrintJobUpdated(PrintJobInfo printJob) {
5084bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann        Message message = mHandlerCaller.obtainMessageO(
5094bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
5104bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                printJob);
5114bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann        mHandlerCaller.executeOrSendMessage(message);
5124bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann
5134bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann        mNotificationController.onUpdateNotifications(mPrintJobs);
5144bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann    }
5154bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann
5162fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        boolean success = false;
518269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
519269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
520269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
521269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
522704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final int oldState = printJob.getState();
523704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                if (oldState == state) {
524704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    return false;
525704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
526704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
527269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                success = true;
528269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
529269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setState(state);
530b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                printJob.setStatus(error);
531a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(false);
532269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
533269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PRINT_JOB_LIFECYCLE) {
534269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
535269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
536269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
5372e3012624b703a653fed44d4dc1b8904406c0d99Philip P. Moltmann                MetricsLogger.histogram(this, PRINT_JOB_STATE_HISTO, state);
538269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                switch (state) {
539269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_COMPLETED:
540269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_CANCELED:
541dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        mPrintJobs.remove(printJob);
5422fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        removePrintJobFileLocked(printJob.getId());
543269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        // $fall-through$
544269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
545269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_FAILED: {
546269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        PrinterId printerId = printJob.getPrinterId();
547269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (printerId != null) {
548269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ComponentName service = printerId.getServiceName();
549269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            if (!hasActivePrintJobsForServiceLocked(service)) {
550269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                sendOnAllPrintJobsForServiceHandled(service);
551269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            }
552269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
553269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    } break;
554269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
555269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_QUEUED: {
556269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        sendOnPrintJobQueued(new PrintJobInfo(printJob));
557269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }  break;
558269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
559269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
560269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
561269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
562269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
563269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
564269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!hasActivePrintJobsLocked()) {
565269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    notifyOnAllPrintJobsHandled();
566269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
567704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
5684bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                notifyPrintJobUpdated(printJob);
569269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
570269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
571269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
572269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return success;
573269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
574269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
575b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann    /**
576b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann     * Set the progress for a print job.
577b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann     *
578b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann     * @param printJobId ID of the print job to update
579b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann     * @param progress the new progress
580b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann     */
581b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann    public void setProgress(@NonNull PrintJobId printJobId,
582b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            @FloatRange(from=0.0, to=1.0) float progress) {
583b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        synchronized (mLock) {
584b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setProgress(progress);
585b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
586b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            mNotificationController.onUpdateNotifications(mPrintJobs);
587b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        }
588b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann    }
589b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
590d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    /**
591d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * Set the status for a print job.
592d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     *
593d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * @param printJobId ID of the print job to update
594d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * @param status the new status
595d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     */
596d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
597d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        synchronized (mLock) {
5984bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
599d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann
6004bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            if (printJob != null) {
6014bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                printJob.setStatus(status);
6024bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                notifyPrintJobUpdated(printJob);
6034bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            }
604d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        }
605d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    }
606d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann
607d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    /**
608d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * Set the status for a print job.
609d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     *
610d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * @param printJobId ID of the print job to update
611d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * @param status the new status as a string resource
612d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     * @param appPackageName app package the resource belongs to
613d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann     */
614d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    public void setStatus(@NonNull PrintJobId printJobId, @StringRes int status,
615d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann            @Nullable CharSequence appPackageName) {
616d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        synchronized (mLock) {
6174bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
618b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
6194bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            if (printJob != null) {
6204bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                printJob.setStatus(status, appPackageName);
6214bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann                notifyPrintJobUpdated(printJob);
6224bd8fac48ed28494ca24e456e20b3058f78e8fe9Philip P. Moltmann            }
623d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        }
624d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann    }
625b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
626269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsLocked() {
627269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
628269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
629269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
630269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (isActiveState(printJob.getState())) {
631269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
632269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
633269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
634269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
635269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
636269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
637269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
638269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
639269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
640269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
64175d28505c8f73a977cc7ae0cc08a60120f7c92b2Svetoslav            if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null
642269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && printJob.getPrinterId().getServiceName().equals(service)) {
643269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
644269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
645269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
646269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
647269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
648269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
6492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private boolean isObsoleteState(int printJobState) {
650a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        return (isTerminalState(printJobState)
6512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED);
6522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
6532fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
6549b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    private boolean isScheduledState(int printJobState) {
6559b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov        return printJobState == PrintJobInfo.STATE_QUEUED
6569b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
6579b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
6589b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    }
6599b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov
660269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean isActiveState(int printJobState) {
661269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJobState == PrintJobInfo.STATE_CREATED
662269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED
663d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
664d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
665269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
666269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
667a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    private boolean isTerminalState(int printJobState) {
6682fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        return printJobState == PrintJobInfo.STATE_COMPLETED
6692fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_CANCELED;
6702fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
6712fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
6722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
673269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
674269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
675269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
676269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String printJobTag = printJob.getTag();
677269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (printJobTag == null) {
678269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag == null) {
679269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        return false;
680269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
681269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } else if (printJobTag.equals(tag)) {
682269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
683269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
684269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setTag(tag);
685269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
686269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
687269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
688269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
689269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
690269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
691269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
692269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
693269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
694a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
695a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        synchronized (mLock) {
696a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
697a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (printJob != null) {
698a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(cancelling);
699a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (shouldPersistPrintJob(printJob)) {
700a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    mPersistanceManager.writeStateLocked();
701a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
702a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mNotificationController.onUpdateNotifications(mPrintJobs);
703a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
704a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                Message message = mHandlerCaller.obtainMessageO(
705a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
706a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        printJob);
707a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mHandlerCaller.executeOrSendMessage(message);
708a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
709a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
710a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
711a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
712a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public void updatePrintJobUserConfigurableOptionsNoPersistence(PrintJobInfo printJob) {
713269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
714a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            final int printJobCount = mPrintJobs.size();
715a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            for (int i = 0; i < printJobCount; i++) {
716a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                PrintJobInfo cachedPrintJob = mPrintJobs.get(i);
717a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                if (cachedPrintJob.getId().equals(printJob.getId())) {
718a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPrinterId(printJob.getPrinterId());
719a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPrinterName(printJob.getPrinterName());
720a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setCopies(printJob.getCopies());
721a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo());
722a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPages(printJob.getPages());
723a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setAttributes(printJob.getAttributes());
724a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions());
725a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    return;
726a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                }
727269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
728a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            throw new IllegalArgumentException("No print job with id:" + printJob.getId());
729269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
730269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
731269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
732269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
733269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
734269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
735269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
736269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void notifyOnAllPrintJobsHandled() {
737269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // This has to run on the tread that is persisting the current state
738269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // since this call may result in the system unbinding from the spooler
739269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // and as a result the spooler process may get killed before the write
740269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // completes.
741269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
742269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
743269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
744269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                sendOnAllPrintJobsHandled();
745269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
746269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
747269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
748269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
749269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
750bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    /**
751bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * Handle that a custom icon for a printer was loaded.
752bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     *
753bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @param printerId the id of the printer the icon belongs to
754bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @param icon the icon that was loaded
755bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
756bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     */
757bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
758bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon);
759bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    }
760bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
761bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    /**
762bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * Get the custom icon for a printer. If the icon is not cached, the icon is
763bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * requested asynchronously. Once it is available the printer is updated.
764bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     *
765bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @param printerId the id of the printer the icon should be loaded for
766bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @return the custom icon to be used for the printer or null if the icon is
767bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     *         not yet available
768bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
769bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     */
770bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    public Icon getCustomPrinterIcon(PrinterId printerId) {
771bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        return mCustomIconCache.getIcon(printerId);
772bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    }
773bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
774bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    /**
775bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     * Clear the custom printer icon cache.
776bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann     */
777bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    public void clearCustomPrinterIconCache() {
778bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        mCustomIconCache.clear();
779bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann    }
780bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
781269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class PersistenceManager {
782269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
783269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
784269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_SPOOLER = "spooler";
785269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_JOB = "job";
786269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
787269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PRINTER_ID = "printerId";
788269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PAGE_RANGE = "pageRange";
789269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_ATTRIBUTES = "attributes";
790269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_DOCUMENT_INFO = "documentInfo";
791269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
792269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_ID = "id";
793269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LABEL = "label";
794773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_LABEL_RES_ID = "labelResId";
795773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_PACKAGE_NAME = "packageName";
796269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_STATE = "state";
797269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_APP_ID = "appId";
798269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TAG = "tag";
799704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_CREATION_TIME = "creationTime";
800269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COPIES = "copies";
801704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_PRINTER_NAME = "printerName";
802704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_STATE_REASON = "stateReason";
803b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        private static final String ATTR_STATUS = "status";
804b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        private static final String ATTR_PROGRESS = "progress";
805a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        private static final String ATTR_CANCELLING = "cancelling";
806269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
807b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TAG_ADVANCED_OPTIONS = "advancedOptions";
808b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TAG_ADVANCED_OPTION = "advancedOption";
809b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_KEY = "key";
810b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_TYPE = "type";
811b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_VALUE = "value";
812b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TYPE_STRING = "string";
813b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TYPE_INT = "int";
814b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
815269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MEDIA_SIZE = "mediaSize";
816269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_RESOLUTION = "resolution";
817269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MARGINS = "margins";
818269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
819269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COLOR_MODE = "colorMode";
820948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav        private static final String ATTR_DUPLEX_MODE = "duplexMode";
821269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
822704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_LOCAL_ID = "localId";
823269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_SERVICE_NAME = "serviceName";
824269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
825269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_WIDTH_MILS = "widthMils";
826269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HEIGHT_MILS = "heightMils";
827269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
828269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HORIZONTAL_DPI = "horizontalDip";
829269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_VERTICAL_DPI = "verticalDpi";
830269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
831269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LEFT_MILS = "leftMils";
832269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TOP_MILS = "topMils";
833269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_RIGHT_MILS = "rightMils";
834269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_BOTTOM_MILS = "bottomMils";
835269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
836269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_START = "start";
837269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_END = "end";
838269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
839269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_NAME = "name";
840269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_PAGE_COUNT = "pageCount";
841269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_CONTENT_TYPE = "contentType";
8427d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov        private static final String ATTR_DATA_SIZE = "dataSize";
843269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
844269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private final AtomicFile mStatePersistFile;
845269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
846269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean mWriteStateScheduled;
847269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
848269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private PersistenceManager() {
849269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mStatePersistFile = new AtomicFile(new File(getFilesDir(),
850269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PERSIST_FILE_NAME));
851269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
852269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
853269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void writeStateLocked() {
8544237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov            if (!PERSISTENCE_MANAGER_ENABLED) {
855269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
856269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
857269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mWriteStateScheduled) {
858269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
859269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
860269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mWriteStateScheduled = true;
861269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            new AsyncTask<Void, Void, Void>() {
862269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                @Override
863269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                protected Void doInBackground(Void... params) {
864269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
865269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mWriteStateScheduled = false;
866269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        doWriteStateLocked();
867269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
868269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return null;
869269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
870269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
871269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
872269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
873269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void doWriteStateLocked() {
874269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
875269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[PERSIST START]");
876269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
877269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileOutputStream out = null;
878269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
879269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                out = mStatePersistFile.startWrite();
880269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
881269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlSerializer serializer = new FastXmlSerializer();
8829e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz                serializer.setOutput(out, StandardCharsets.UTF_8.name());
883269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startDocument(null, true);
884269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startTag(null, TAG_SPOOLER);
885269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
886269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                List<PrintJobInfo> printJobs = mPrintJobs;
887269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
888269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int printJobCount = printJobs.size();
889269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                for (int j = 0; j < printJobCount; j++) {
890269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintJobInfo printJob = printJobs.get(j);
891269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
892885810de69d75979df4299d21fa236490767eae4Svetoslav                    if (!shouldPersistPrintJob(printJob)) {
893885810de69d75979df4299d21fa236490767eae4Svetoslav                        continue;
894885810de69d75979df4299d21fa236490767eae4Svetoslav                    }
895885810de69d75979df4299d21fa236490767eae4Svetoslav
896269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.startTag(null, TAG_JOB);
897269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
8982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
899269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
900269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
901269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
902269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String tag = printJob.getTag();
903269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag != null) {
904269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_TAG, tag);
905269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
906704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf(
907704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            printJob.getCreationTime()));
908269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
909704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    String printerName = printJob.getPrinterName();
910704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (!TextUtils.isEmpty(printerName)) {
911704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
912704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
913a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    serializer.attribute(null, ATTR_CANCELLING, String.valueOf(
914a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.isCancelling()));
915269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
916b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                    float progress = printJob.getProgress();
917310ddc313fc1a1251c4ebd09868d5b4c7d0a3cf7Ian Rogers                    if (!Float.isNaN(progress)) {
918b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                        serializer.attribute(null, ATTR_PROGRESS, String.valueOf(progress));
919b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                    }
920b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
921d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann                    CharSequence status = printJob.getStatus(getPackageManager());
922b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                    if (!TextUtils.isEmpty(status)) {
923b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                        serializer.attribute(null, ATTR_STATUS, status.toString());
924b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                    }
925b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
926269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrinterId printerId = printJob.getPrinterId();
927269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printerId != null) {
928269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_PRINTER_ID);
929269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
930269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
931269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                .flattenToString());
932269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_PRINTER_ID);
933269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
934269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
935269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PageRange[] pages = printJob.getPages();
936269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (pages != null) {
937269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        for (int i = 0; i < pages.length; i++) {
938269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_PAGE_RANGE);
939269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_START, String.valueOf(
940269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getStart()));
941269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_END, String.valueOf(
942269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getEnd()));
943269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_PAGE_RANGE);
944269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
945269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
946269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
947269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintAttributes attributes = printJob.getAttributes();
948269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (attributes != null) {
949269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_ATTRIBUTES);
950269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
951269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int colorMode = attributes.getColorMode();
952269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_COLOR_MODE,
953269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                String.valueOf(colorMode));
954269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
955948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                        final int duplexMode = attributes.getDuplexMode();
956948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                        serializer.attribute(null, ATTR_DUPLEX_MODE,
957948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                                String.valueOf(duplexMode));
958948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav
959269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        MediaSize mediaSize = attributes.getMediaSize();
960269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mediaSize != null) {
961269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MEDIA_SIZE);
962269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, mediaSize.getId());
963269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(
964269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getWidthMils()));
965269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf(
966269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getHeightMils()));
967a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // We prefer to store only the package name and
968a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // resource id and fallback to the label.
969a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            if (!TextUtils.isEmpty(mediaSize.mPackageName)
970773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                    && mediaSize.mLabelResId > 0) {
971773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_PACKAGE_NAME,
972773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.mPackageName);
973773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL_RES_ID,
974773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        String.valueOf(mediaSize.mLabelResId));
975773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            } else {
976773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL,
977773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.getLabel(getPackageManager()));
978773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            }
979269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MEDIA_SIZE);
980269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
981269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
982269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Resolution resolution = attributes.getResolution();
983269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (resolution != null) {
984269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_RESOLUTION);
985269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, resolution.getId());
986269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf(
987269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getHorizontalDpi()));
988269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
989269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getVerticalDpi()));
990c6066799ad130140159230d14451b429eb828755Svetoslav                            serializer.attribute(null, ATTR_LABEL,
991651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                                    resolution.getLabel());
992269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_RESOLUTION);
993269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
994269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
995651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        Margins margins = attributes.getMinMargins();
996269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (margins != null) {
997269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MARGINS);
998269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
999269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getLeftMils()));
1000269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(
1001269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getTopMils()));
1002269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(
1003269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getRightMils()));
1004269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(
1005269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getBottomMils()));
1006269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MARGINS);
1007269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
1008269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1009269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_ATTRIBUTES);
1010269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
1011269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1012269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
1013269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (documentInfo != null) {
1014269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_DOCUMENT_INFO);
1015269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_NAME, documentInfo.getName());
1016269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf(
1017269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getContentType()));
1018269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf(
1019269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getPageCount()));
10207d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                        serializer.attribute(null, ATTR_DATA_SIZE, String.valueOf(
10217d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                                documentInfo.getDataSize()));
1022269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_DOCUMENT_INFO);
1023269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
1024269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1025b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    Bundle advancedOptions = printJob.getAdvancedOptions();
1026b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    if (advancedOptions != null) {
1027b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        serializer.startTag(null, TAG_ADVANCED_OPTIONS);
1028b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        for (String key : advancedOptions.keySet()) {
1029b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            Object value = advancedOptions.get(key);
1030b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            if (value instanceof String) {
1031b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                String stringValue = (String) value;
1032b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.startTag(null, TAG_ADVANCED_OPTION);
1033b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_KEY, key);
1034b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_TYPE, TYPE_STRING);
1035b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_VALUE, stringValue);
1036b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.endTag(null, TAG_ADVANCED_OPTION);
1037b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            } else if (value instanceof Integer) {
1038b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                String intValue = Integer.toString((Integer) value);
1039b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.startTag(null, TAG_ADVANCED_OPTION);
1040b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_KEY, key);
1041b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_TYPE, TYPE_INT);
1042b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_VALUE, intValue);
1043b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.endTag(null, TAG_ADVANCED_OPTION);
1044b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            }
1045b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        }
1046b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        serializer.endTag(null, TAG_ADVANCED_OPTIONS);
1047b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    }
1048b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
1049269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.endTag(null, TAG_JOB);
1050269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1051269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (DEBUG_PERSISTENCE) {
1052269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Log.i(LOG_TAG, "[PERSISTED] " + printJob);
1053269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
1054269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1055269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1056269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endTag(null, TAG_SPOOLER);
1057269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endDocument();
1058269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.finishWrite(out);
1059269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PERSISTENCE) {
1060269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.i(LOG_TAG, "[PERSIST END]");
1061269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1062269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException e) {
1063269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
1064269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.failWrite(out);
1065269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
1066269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(out);
1067269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1068269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1069269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1070269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void readStateLocked() {
10714237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov            if (!PERSISTENCE_MANAGER_ENABLED) {
1072269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
1073269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1074269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileInputStream in = null;
1075269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
1076269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                in = mStatePersistFile.openRead();
1077269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (FileNotFoundException e) {
107813460a6cba25b99c405d00bb40939958df332f3fJoe Onorato                if (DEBUG_PERSISTENCE) {
107913460a6cba25b99c405d00bb40939958df332f3fJoe Onorato                    Log.d(LOG_TAG, "No existing print spooler state.");
108013460a6cba25b99c405d00bb40939958df332f3fJoe Onorato                }
1081269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
1082269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1083269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
1084269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlPullParser parser = Xml.newPullParser();
10859e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz                parser.setInput(in, StandardCharsets.UTF_8.name());
1086269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parseState(parser);
1087269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IllegalStateException ise) {
1088269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ise);
1089269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NullPointerException npe) {
1090269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", npe);
1091269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NumberFormatException nfe) {
1092269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", nfe);
1093269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (XmlPullParserException xppe) {
1094269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", xppe);
1095269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException ioe) {
1096269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ioe);
1097269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IndexOutOfBoundsException iobe) {
1098269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", iobe);
1099269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
1100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(in);
1101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void parseState(XmlPullParser parser)
1105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
1107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER);
1109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
1110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1111269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (parsePrintJob(parser)) {
1112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1116269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER);
1117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean parsePrintJob(XmlPullParser parser)
1120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
1123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1126269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = new PrintJobInfo();
1127269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
11282fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            PrintJobId printJobId = PrintJobId.unflattenFromString(
11292fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    parser.getAttributeValue(null, ATTR_ID));
1130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setId(printJobId);
1131269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String label = parser.getAttributeValue(null, ATTR_LABEL);
1132269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setLabel(label);
1133269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
1134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setState(state);
1135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
1136269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setAppId(appId);
1137269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String tag = parser.getAttributeValue(null, ATTR_TAG);
1138269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setTag(tag);
1139704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
1140704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setCreationTime(Long.parseLong(creationTime));
1141269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String copies = parser.getAttributeValue(null, ATTR_COPIES);
1142269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setCopies(Integer.parseInt(copies));
1143704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
1144704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setPrinterName(printerName);
1145b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1146b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            String progressString = parser.getAttributeValue(null, ATTR_PROGRESS);
1147b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            if (progressString != null) {
1148b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                float progress = Float.parseFloat(progressString);
1149b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1150a958fc336b277cf2838ccd50ef3d3484644b100aPhilip P. Moltmann                if (progress != -1) {
1151b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                    printJob.setProgress(progress);
1152b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                }
1153b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            }
1154b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1155b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            CharSequence status = parser.getAttributeValue(null, ATTR_STATUS);
1156b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            printJob.setStatus(status);
1157b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1158b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            // stateReason is deprecated, but might be used by old print jobs
1159704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
1160b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            if (stateReason != null) {
1161b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                printJob.setStatus(stateReason);
1162b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            }
1163b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1164a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
1165a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            printJob.setCancelling(!TextUtils.isEmpty(cancelling)
1166a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    ? Boolean.parseBoolean(cancelling) : false);
1167269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1168269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
1169269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1170269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1171269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
1172269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
1173269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
1174269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        null, ATTR_SERVICE_NAME));
1175269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPrinterId(new PrinterId(service, localId));
1176269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1177269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1178269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
1179269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1180269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1181269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1182269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1183269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            List<PageRange> pageRanges = null;
1184269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
1185269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
1186269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
1187269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange pageRange = new PageRange(start, end);
1188269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (pageRanges == null) {
1189269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    pageRanges = new ArrayList<PageRange>();
1190269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.add(pageRange);
1192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
1195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1196b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (pageRanges != null) {
1199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
1200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.toArray(pageRangesArray);
1201269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPages(pageRangesArray);
1202269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1203269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1204269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1205269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {
1206269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1207269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintAttributes.Builder builder = new PrintAttributes.Builder();
1208269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1209269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
1210269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                builder.setColorMode(Integer.parseInt(colorMode));
1211269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1212948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE);
1213948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                // Duplex mode was added later, so null check is needed.
1214948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                if (duplexMode != null) {
1215948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                    builder.setDuplexMode(Integer.parseInt(duplexMode));
1216948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav                }
1217948c9a6393e0995a4d988d5d164998aa0e12b25dSvetoslav
1218269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1219269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1220269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1221269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
1222269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1223269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1224269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int widthMils = Integer.parseInt(parser.getAttributeValue(null,
1225269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_WIDTH_MILS));
1226269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int heightMils = Integer.parseInt(parser.getAttributeValue(null,
1227269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HEIGHT_MILS));
1228773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
1229b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID);
1230b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    final int labelResId = (labelResIdString != null)
1231b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                            ? Integer.parseInt(labelResIdString) : 0;
1232773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1233b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    MediaSize mediaSize = new MediaSize(id, label, packageName,
1234b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                widthMils, heightMils, labelResId);
1235269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setMediaSize(mediaSize);
1236269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1237269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1238269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
1239269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1240269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1241269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1242269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1243269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
1244269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1245269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1246269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null,
1247269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HORIZONTAL_DPI));
1248269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
1249269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_VERTICAL_DPI));
1250c6066799ad130140159230d14451b429eb828755Svetoslav                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
1251269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setResolution(resolution);
1252269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1253269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1254269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
1255269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1256269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1257269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1258269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1259269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
1260269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int leftMils = Integer.parseInt(parser.getAttributeValue(null,
1261269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_LEFT_MILS));
1262269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int topMils = Integer.parseInt(parser.getAttributeValue(null,
1263269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_TOP_MILS));
1264269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int rightMils = Integer.parseInt(parser.getAttributeValue(null,
1265269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_RIGHT_MILS));
1266269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
1267269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_BOTTOM_MILS));
1268269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
1269651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                    builder.setMinMargins(margins);
1270269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1271269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1272269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
1273269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1274269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1275269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1276651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                printJob.setAttributes(builder.build());
1277269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1278269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1279269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
1280269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1281269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
1285269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String name = parser.getAttributeValue(null, ATTR_NAME);
1286269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int pageCount = Integer.parseInt(parser.getAttributeValue(null,
1287269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_PAGE_COUNT));
1288269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int contentType = Integer.parseInt(parser.getAttributeValue(null,
1289269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_CONTENT_TYPE));
12907d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                final int dataSize = Integer.parseInt(parser.getAttributeValue(null,
12917d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                        ATTR_DATA_SIZE));
1292269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintDocumentInfo info = new PrintDocumentInfo.Builder(name)
1293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        .setPageCount(pageCount)
1294651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        .setContentType(contentType).build();
1295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setDocumentInfo(info);
12967d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                info.setDataSize(dataSize);
1297269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1298269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1299269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
1300269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1301269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1302269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1303b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            skipEmptyTextTags(parser);
1304b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTIONS)) {
1305b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                parser.next();
1306b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1307b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                Bundle advancedOptions = new Bundle();
1308b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                while (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTION)) {
1309b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String key = parser.getAttributeValue(null, ATTR_KEY);
1310b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String value = parser.getAttributeValue(null, ATTR_VALUE);
1311b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String type = parser.getAttributeValue(null, ATTR_TYPE);
1312b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    if (TYPE_STRING.equals(type)) {
1313b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        advancedOptions.putString(key, value);
1314b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    } else if (TYPE_INT.equals(type)) {
13159bbbf2b15f331e8c72ee1054dc0ef6a613921fe1Tobias Thierer                        advancedOptions.putInt(key, Integer.parseInt(value));
1316b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    }
1317b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    parser.next();
1318b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    skipEmptyTextTags(parser);
1319b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTION);
1320b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    parser.next();
1321b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    skipEmptyTextTags(parser);
1322b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                }
1323b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                printJob.setAdvancedOptions(advancedOptions);
1324b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1325b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTIONS);
1326b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                parser.next();
1327b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            }
1328b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
1329269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPrintJobs.add(printJob);
1330269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1331269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
1332269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[RESTORED] " + printJob);
1333269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1334269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1335269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1336269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_JOB);
1337269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1338269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1339269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1340269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1341269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void expect(XmlPullParser parser, int type, String tag)
1342c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann                throws XmlPullParserException {
1343269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, type, tag)) {
1344269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throw new XmlPullParserException("Exepected event: " + type
1345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag: " + tag + " but got event: " + parser.getEventType()
1346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag:" + parser.getName());
1347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1348269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1349269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1350269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void skipEmptyTextTags(XmlPullParser parser)
1351269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1352269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.TEXT, null)
1353269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && "\n".equals(parser.getText())) {
1354269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1355269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1356269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1357269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1358269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean accept(XmlPullParser parser, int type, String tag)
1359c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann                throws XmlPullParserException {
1360269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (parser.getEventType() != type) {
1361269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1362269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1363269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (tag != null) {
1364269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!tag.equals(parser.getName())) {
1365269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
1366269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1367269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } else if (parser.getName() != null) {
1368269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1369269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1370269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1371269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1372269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
13737bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
1374a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public final class PrintSpooler extends IPrintSpooler.Stub {
13757bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
13767bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
13777bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                ComponentName componentName, int state, int appId, int sequence)
13787bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                throws RemoteException {
13797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            List<PrintJobInfo> printJobs = null;
13807bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
13817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJobs = PrintSpoolerService.this.getPrintJobInfos(
13827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        componentName, state, appId);
13837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
13847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfosResult(printJobs, sequence);
13857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
13867bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
13877bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
13887bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
13897bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
13907bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                int appId, int sequence) throws RemoteException {
13917bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintJobInfo printJob = null;
13927bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
13937bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
13947bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
13957bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfoResult(printJob, sequence);
13967bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
13977bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
13987bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
13997bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void createPrintJob(PrintJobInfo printJob) {
14017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.createPrintJob(printJob);
14027bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14037bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14057bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobState(PrintJobId printJobId, int state, String error,
14067bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
14077bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
14087bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
14097bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobState(
14107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        printJobId, state, error);
14117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
14127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobStateResult(success, sequece);
14137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
14147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobTag(PrintJobId printJobId, String tag,
14187bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
14197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
14207bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
14217bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
14227bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
14237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobTagResult(success, sequece);
14247bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
14257bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14267bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14277bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14287bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
14297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.writePrintJobData(fd, printJobId);
14307bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14317bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14337bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setClient(IPrintSpoolerClient client) {
14347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
14357bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_SET_CLIENT, client);
14367bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
14377bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14397bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void removeObsoletePrintJobs() {
14417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.removeObsoletePrintJobs();
14427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14437bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14447bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14457bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
14467bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.dump(fd, writer, args);
14477bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
14497bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
14507bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
14517bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
14527bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
14537bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
1454853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        @Override
14558141bdfa56f13c3946bed12ba7801e492ec25c11Philip P. Moltmann        public void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) {
1456853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann            (new ApprovedPrintServices(PrintSpoolerService.this))
14578141bdfa56f13c3946bed12ba7801e492ec25c11Philip P. Moltmann                    .pruneApprovedServices(servicesToKeep);
1458853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann        }
1459853a6f564abaf8acbd88c6704008c5d150d00471Philip P. Moltmann
1460b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        @Override
1461b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        public void setProgress(@NonNull PrintJobId printJobId,
1462b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                @FloatRange(from=0.0, to=1.0) float progress) throws RemoteException {
1463b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            PrintSpoolerService.this.setProgress(printJobId, progress);
1464b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        }
1465b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1466b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        @Override
1467b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        public void setStatus(@NonNull PrintJobId printJobId,
1468b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann                @Nullable CharSequence status) throws RemoteException {
1469b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann            PrintSpoolerService.this.setStatus(printJobId, status);
1470b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann        }
1471b3078c235e7674fd61be75fb469105ba6174aba5Philip P. Moltmann
1472d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        @Override
1473d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        public void setStatusRes(@NonNull PrintJobId printJobId, @StringRes int status,
1474d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann                @NonNull CharSequence appPackageName) throws RemoteException {
1475d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann            PrintSpoolerService.this.setStatus(printJobId, status, appPackageName);
1476d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann        }
1477d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann
1478d74d1e549168ba521e8009961b76e8718be37aa1Philip P. Moltmann
14797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public PrintSpoolerService getService() {
14807bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return PrintSpoolerService.this;
14817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
1482bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
1483bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        @Override
1484bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon,
1485bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                IPrintSpoolerCallbacks callbacks, int sequence)
1486bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                throws RemoteException {
1487bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            try {
1488bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                PrintSpoolerService.this.onCustomPrinterIconLoaded(printerId, icon);
1489bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            } finally {
1490bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                callbacks.onCustomPrinterIconCached(sequence);
1491bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            }
1492bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        }
1493bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
1494bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        @Override
1495bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        public void getCustomPrinterIcon(PrinterId printerId, IPrintSpoolerCallbacks callbacks,
1496bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                int sequence) throws RemoteException {
1497bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            Icon icon = null;
1498bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            try {
1499bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                icon = PrintSpoolerService.this.getCustomPrinterIcon(printerId);
1500bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            } finally {
1501bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                callbacks.onGetCustomPrinterIconResult(icon, sequence);
1502bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            }
1503bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        }
1504bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
1505bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        @Override
1506bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        public void clearCustomPrinterIconCache(IPrintSpoolerCallbacks callbacks,
1507bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                int sequence) throws RemoteException {
1508bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            try {
1509bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                PrintSpoolerService.this.clearCustomPrinterIconCache();
1510bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            } finally {
1511bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann                callbacks.customPrinterIconCacheCleared(sequence);
1512bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann            }
1513bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann        }
1514bb9f686b40743df2642b7d3b7778dbf7284ae665Philip P. Moltmann
15157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    }
15164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
1517