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