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
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Service;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName;
21a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslavimport android.content.Context;
224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent;
23269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.os.AsyncTask;
24b4fda134761c9521a7e127db3806a07a18763b77Svetoslavimport android.os.Bundle;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.IBinder;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.ParcelFileDescriptor;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException;
29a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpooler;
30a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerCallbacks;
31835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.print.IPrintSpoolerClient;
32269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PageRange;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintAttributes;
34269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Margins;
35269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.MediaSize;
36269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Resolution;
37269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintDocumentInfo;
382fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo;
40269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintManager;
41269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrinterId;
42a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslavimport android.text.TextUtils;
43dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport android.util.ArrayMap;
44269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.AtomicFile;
45835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.util.Log;
464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Slog;
47269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.Xml;
484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
49269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.os.HandlerCaller;
50269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.util.FastXmlSerializer;
51a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslavimport com.android.printspooler.R;
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
532fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport libcore.io.IoUtils;
542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
55269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParser;
56269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParserException;
57269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlSerializer;
58269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
59269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.File;
60dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.FileDescriptor;
61269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileInputStream;
62269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileNotFoundException;
63269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileOutputStream;
64269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.IOException;
65dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.PrintWriter;
66269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.util.ArrayList;
67835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport java.util.List;
68835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Service for exposing some of the {@link PrintSpooler} functionality to
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * another process.
724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic final class PrintSpoolerService extends Service {
744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
75269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final String LOG_TAG = "PrintSpoolerService";
76269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
77b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav    private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
78269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
79c6066799ad130140159230d14451b429eb828755Svetoslav    private static final boolean DEBUG_PERSISTENCE = false;
80269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
814237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    private static final boolean PERSISTENCE_MANAGER_ENABLED = true;
82269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
83835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000;
84835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
85dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private static final String PRINT_JOB_FILE_PREFIX = "print_job_";
86dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
87269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final String PRINT_FILE_EXTENSION = "pdf";
88269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
89269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final Object sLock = new Object();
90269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
91269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final Object mLock = new Object();
92269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
93a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    private final List<PrintJobInfo> mPrintJobs = new ArrayList<>();
94269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
95269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static PrintSpoolerService sInstance;
96269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
97835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private IPrintSpoolerClient mClient;
984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
99269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private HandlerCaller mHandlerCaller;
100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private PersistenceManager mPersistanceManager;
102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private NotificationController mNotificationController;
104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public static PrintSpoolerService peekInstance() {
106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return sInstance;
108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public void onCreate() {
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        super.onCreate();
114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller = new HandlerCaller(this, getMainLooper(),
115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                new HandlerCallerCallback(), false);
116269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPersistanceManager = new PersistenceManager();
118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mNotificationController = new NotificationController(PrintSpoolerService.this);
119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPersistanceManager.readStateLocked();
122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            handleReadPrintJobsLocked();
123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
126269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            sInstance = this;
127269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public IBinder onBind(Intent intent) {
1327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        return new PrintSpooler();
1334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
135dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    @Override
136dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
137dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        synchronized (mLock) {
138b67a637e60c356ab520050b2bd09a95ae47f3017Svetoslav            String prefix = (args.length > 0) ? args[0] : "";
139dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            String tab = "  ";
140dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
141dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print jobs:").println();
142dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int printJobCount = mPrintJobs.size();
143dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < printJobCount; i++) {
144dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                PrintJobInfo printJob = mPrintJobs.get(i);
145dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.append(prefix).append(tab).append(printJob.toString());
146dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.println();
147dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
148dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
149dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print job files:").println();
150dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            File[] files = getFilesDir().listFiles();
151dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (files != null) {
152dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int fileCount = files.length;
153dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < fileCount; i++) {
154dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    File file = files[i];
155dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
156dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        pw.append(prefix).append(tab).append(file.getName()).println();
157dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
158dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
159dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
160dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
161dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    }
162dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
163269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnPrintJobQueued(PrintJobInfo printJob) {
164269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
165269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
166269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
167269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
168269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
169269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsForServiceHandled(ComponentName service) {
170269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
171269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service);
172269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
173269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
174269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
175269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsHandled() {
176269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessage(
177269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED);
178269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
179269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
180269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
181269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class HandlerCallerCallback implements HandlerCaller.Callback {
182704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public static final int MSG_SET_CLIENT = 1;
1837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_QUEUED = 2;
1847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 3;
1857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 4;
1867bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 5;
1877bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 6;
1884b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1894b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
190269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void executeMessage(Message message) {
191835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            switch (message.what) {
192835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_SET_CLIENT: {
193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mClient = (IPrintSpoolerClient) message.obj;
195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mClient != null) {
196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            Message msg = mHandlerCaller.obtainMessage(
197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED);
198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            mHandlerCaller.sendMessageDelayed(msg,
199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    CHECK_ALL_PRINTJOBS_HANDLED_DELAY);
200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
201835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
202835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
203835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
204835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_PRINT_JOB_QUEUED: {
205835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
206835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
207835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
208835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onPrintJobQueued(printJob);
209835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
210835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
211835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
212835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
213835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
214835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
215835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: {
216835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    ComponentName service = (ComponentName) message.obj;
217835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
218835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
219835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsForServiceHandled(service);
220835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
221835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print jobs per service"
222835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                    + " handled.", re);
223835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
224835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
225835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
226835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
227835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
228835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
229835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
230835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsHandled();
231835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
232835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
233835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
234835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
235835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
236835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
237835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
238269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    checkAllPrintJobsHandled();
239269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
240704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
241704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                case MSG_ON_PRINT_JOB_STATE_CHANGED: {
242704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (mClient != null) {
243dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        PrintJobInfo printJob = (PrintJobInfo) message.obj;
244704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        try {
245dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            mClient.onPrintJobStateChanged(printJob);
246704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        } catch (RemoteException re) {
247704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for print job state change.", re);
248704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        }
249704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
250704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                } break;
2514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
2524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
254269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
255269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName,
256269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            int state, int appId) {
257269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        List<PrintJobInfo> foundPrintJobs = null;
258269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
259269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
260269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
261269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
262269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrinterId printerId = printJob.getPrinterId();
263269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameComponent = (componentName == null
264269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (printerId != null
265269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && componentName.equals(printerId.getServiceName())));
266269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameAppId = appId == PrintManager.APP_ID_ANY
267269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || printJob.getAppId() == appId;
268269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameState = (state == printJob.getState())
269269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY)
270269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
271d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                            && isStateVisibleToUser(printJob.getState()))
272d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_ACTIVE
2739b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isActiveState(printJob.getState()))
2749b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_SCHEDULED
2759b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isScheduledState(printJob.getState()));
276269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (sameComponent && sameAppId && sameState) {
277269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (foundPrintJobs == null) {
278a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                        foundPrintJobs = new ArrayList<>();
279269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
280269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    foundPrintJobs.add(printJob);
281269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return foundPrintJobs;
285269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
286269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
287d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private boolean isStateVisibleToUser(int state) {
288d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
2892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
2902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_BLOCKED));
291d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
292d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
2932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
294269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
296269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
297269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
2982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (printJob.getId().equals(printJobId)
299269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && (appId == PrintManager.APP_ID_ANY
300269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || appId == printJob.getAppId())) {
301269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return printJob;
302269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
303269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
304269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return null;
305269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
306269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
307269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3082fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void createPrintJob(PrintJobInfo printJob) {
309269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
310269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            addPrintJobLocked(printJob);
311dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
3127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
3137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
3147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
3157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    printJob);
3167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
317269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
318269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
319269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
320269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void handleReadPrintJobsLocked() {
321dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Make a map with the files for a print job since we may have
322dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // to delete some. One example of getting orphan files if the
323dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // spooler crashes while constructing a print job. We do not
324dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // persist partially populated print jobs under construction to
325dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // avoid special handling for various attributes missing.
326dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        ArrayMap<PrintJobId, File> fileForJobMap = null;
327dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        File[] files = getFilesDir().listFiles();
328dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (files != null) {
329dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int fileCount = files.length;
330dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < fileCount; i++) {
331dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = files[i];
332dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
333dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (fileForJobMap == null) {
334dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        fileForJobMap = new ArrayMap<PrintJobId, File>();
335dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
3362b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                    String printJobIdString = file.getName().substring(
3372b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            PRINT_JOB_FILE_PREFIX.length(),
3382b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            file.getName().indexOf('.'));
339dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    PrintJobId printJobId = PrintJobId.unflattenFromString(
340dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            printJobIdString);
341dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    fileForJobMap.put(printJobId, file);
342dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
343dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
344dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
345dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
348269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
349269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
350dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            // We want to have only the orphan files at the end.
351dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (fileForJobMap != null) {
352dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                fileForJobMap.remove(printJob.getId());
353dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
354dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
355269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            switch (printJob.getState()) {
356269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case PrintJobInfo.STATE_QUEUED:
357d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_STARTED:
358d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_BLOCKED: {
359d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // We have a print job that was queued or started or blocked in
360d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // the past but the device battery died or a crash occurred. In
361d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // this case we assume the print job failed and let the user
362d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // decide whether to restart the job or just cancel it.
363269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
364269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            getString(R.string.no_connection_to_printer));
3652fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                } break;
366269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
367269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
368dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
369a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        if (!mPrintJobs.isEmpty()) {
370a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            // Update the notification.
371a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            mNotificationController.onUpdateNotifications(mPrintJobs);
372a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
373a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
374dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Delete the orphan files.
375dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (fileForJobMap != null) {
376dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int orphanFileCount = fileForJobMap.size();
377dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < orphanFileCount; i++) {
378dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = fileForJobMap.valueAt(i);
379dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                file.delete();
380dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
381dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
382269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
383269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
384269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public void checkAllPrintJobsHandled() {
385269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
386269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!hasActivePrintJobsLocked()) {
387269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                notifyOnAllPrintJobsHandled();
388269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
389269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
390269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
391269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
393269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final PrintJobInfo printJob;
394269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
395269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
396269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
397269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
398269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
399269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
400269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileInputStream in = null;
401269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileOutputStream out = null;
402269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                try {
403269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printJob != null) {
404a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                        File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
405269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        in = new FileInputStream(file);
406269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out = new FileOutputStream(fd.getFileDescriptor());
407269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
408269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final byte[] buffer = new byte[8192];
409269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    while (true) {
410269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int readByteCount = in.read(buffer);
411269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (readByteCount < 0) {
412269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            return null;
413269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
414269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out.write(buffer, 0, readByteCount);
415269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
416269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (FileNotFoundException fnfe) {
417269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", fnfe);
418269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (IOException ioe) {
419269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", ioe);
420269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } finally {
421269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(in);
422269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(out);
423269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(fd);
424269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
425269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[END WRITE]");
426269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
427269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
428269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
429269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
430269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
431a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public static File generateFileForPrintJob(Context context, PrintJobId printJobId) {
432a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        return new File(context.getFilesDir(), PRINT_JOB_FILE_PREFIX
4332fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
434269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
435269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
436269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void addPrintJobLocked(PrintJobInfo printJob) {
437269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPrintJobs.add(printJob);
438269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (DEBUG_PRINT_JOB_LIFECYCLE) {
439269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            Slog.i(LOG_TAG, "[ADD] " + printJob);
440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
441269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
442269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removeObsoletePrintJobs() {
4442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        synchronized (mLock) {
445885810de69d75979df4299d21fa236490767eae4Svetoslav            boolean persistState = false;
4462fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            final int printJobCount = mPrintJobs.size();
4472fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            for (int i = printJobCount - 1; i >= 0; i--) {
4482fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
4492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (isObsoleteState(printJob.getState())) {
4502fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    mPrintJobs.remove(i);
4512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    if (DEBUG_PRINT_JOB_LIFECYCLE) {
4522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
4532fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    }
4542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    removePrintJobFileLocked(printJob.getId());
455885810de69d75979df4299d21fa236490767eae4Svetoslav                    persistState = true;
4562fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                }
4572fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
458885810de69d75979df4299d21fa236490767eae4Svetoslav            if (persistState) {
459885810de69d75979df4299d21fa236490767eae4Svetoslav                mPersistanceManager.writeStateLocked();
460885810de69d75979df4299d21fa236490767eae4Svetoslav            }
4612fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
4622fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
4632fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
4642fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removePrintJobFileLocked(PrintJobId printJobId) {
465a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
4662fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (file.exists()) {
4672fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            file.delete();
468269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PRINT_JOB_LIFECYCLE) {
469dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
470269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
471269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
472269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
473269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
475269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        boolean success = false;
476269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
477269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
478269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
479269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
480704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final int oldState = printJob.getState();
481704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                if (oldState == state) {
482704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    return false;
483704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
484704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
485269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                success = true;
486269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
487269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setState(state);
488d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                printJob.setStateReason(error);
489a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(false);
490269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
491269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PRINT_JOB_LIFECYCLE) {
492269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
493269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
494269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
495269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                switch (state) {
496269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_COMPLETED:
497269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_CANCELED:
498dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        mPrintJobs.remove(printJob);
4992fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        removePrintJobFileLocked(printJob.getId());
500269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        // $fall-through$
501269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
502269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_FAILED: {
503269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        PrinterId printerId = printJob.getPrinterId();
504269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (printerId != null) {
505269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ComponentName service = printerId.getServiceName();
506269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            if (!hasActivePrintJobsForServiceLocked(service)) {
507269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                sendOnAllPrintJobsForServiceHandled(service);
508269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            }
509269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
510269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    } break;
511269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
512269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_QUEUED: {
513269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        sendOnPrintJobQueued(new PrintJobInfo(printJob));
514269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }  break;
515269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
516269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
518269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
519269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
520269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
521269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!hasActivePrintJobsLocked()) {
522269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    notifyOnAllPrintJobsHandled();
523269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
524704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
525dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                Message message = mHandlerCaller.obtainMessageO(
526704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
527dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJob);
528704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                mHandlerCaller.executeOrSendMessage(message);
529a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
530a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mNotificationController.onUpdateNotifications(mPrintJobs);
531269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
532269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
533269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
534269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return success;
535269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
536269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
537269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsLocked() {
538269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
539269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
540269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
541269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (isActiveState(printJob.getState())) {
542269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
543269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
544269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
545269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
546269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
547269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
548269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
549269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
550269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
551269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
55275d28505c8f73a977cc7ae0cc08a60120f7c92b2Svetoslav            if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null
553269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && printJob.getPrinterId().getServiceName().equals(service)) {
554269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
555269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
556269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
557269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
558269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
559269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
5602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private boolean isObsoleteState(int printJobState) {
561a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav        return (isTerminalState(printJobState)
5622fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED);
5632fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
5642fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
5659b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    private boolean isScheduledState(int printJobState) {
5669b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov        return printJobState == PrintJobInfo.STATE_QUEUED
5679b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
5689b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
5699b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    }
5709b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov
571269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean isActiveState(int printJobState) {
572269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJobState == PrintJobInfo.STATE_CREATED
573269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED
574d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
575d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
576269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
577269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
578a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    private boolean isTerminalState(int printJobState) {
5792fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        return printJobState == PrintJobInfo.STATE_COMPLETED
5802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_CANCELED;
5812fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
5822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
5832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
584269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
585269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
586269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
587269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String printJobTag = printJob.getTag();
588269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (printJobTag == null) {
589269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag == null) {
590269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        return false;
591269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
592269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } else if (printJobTag.equals(tag)) {
593269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
594269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
595269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setTag(tag);
596269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
597269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
598269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
599269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
600269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
601269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
602269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
603269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
604269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
605a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
606a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        synchronized (mLock) {
607a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
608a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (printJob != null) {
609a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(cancelling);
610a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (shouldPersistPrintJob(printJob)) {
611a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    mPersistanceManager.writeStateLocked();
612a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
613a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mNotificationController.onUpdateNotifications(mPrintJobs);
614a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
615a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                Message message = mHandlerCaller.obtainMessageO(
616a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
617a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        printJob);
618a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mHandlerCaller.executeOrSendMessage(message);
619a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
620a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
621a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
622a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
623a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public void updatePrintJobUserConfigurableOptionsNoPersistence(PrintJobInfo printJob) {
624269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
625a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            final int printJobCount = mPrintJobs.size();
626a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            for (int i = 0; i < printJobCount; i++) {
627a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                PrintJobInfo cachedPrintJob = mPrintJobs.get(i);
628a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                if (cachedPrintJob.getId().equals(printJob.getId())) {
629a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPrinterId(printJob.getPrinterId());
630a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPrinterName(printJob.getPrinterName());
631a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setCopies(printJob.getCopies());
632a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo());
633a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setPages(printJob.getPages());
634a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setAttributes(printJob.getAttributes());
635a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions());
636a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                    return;
637a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                }
638269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
639a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav            throw new IllegalArgumentException("No print job with id:" + printJob.getId());
640269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
641269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
642269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
643269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
644269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
645269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
646269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
647269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void notifyOnAllPrintJobsHandled() {
648269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // This has to run on the tread that is persisting the current state
649269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // since this call may result in the system unbinding from the spooler
650269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // and as a result the spooler process may get killed before the write
651269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // completes.
652269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
653269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
654269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
655269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                sendOnAllPrintJobsHandled();
656269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
657269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
658269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
659269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
660269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
661269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class PersistenceManager {
662269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
663269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
664269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_SPOOLER = "spooler";
665269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_JOB = "job";
666269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
667269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PRINTER_ID = "printerId";
668269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PAGE_RANGE = "pageRange";
669269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_ATTRIBUTES = "attributes";
670269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_DOCUMENT_INFO = "documentInfo";
671269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
672269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_ID = "id";
673269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LABEL = "label";
674773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_LABEL_RES_ID = "labelResId";
675773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_PACKAGE_NAME = "packageName";
676269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_STATE = "state";
677269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_APP_ID = "appId";
678269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TAG = "tag";
679704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_CREATION_TIME = "creationTime";
680269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COPIES = "copies";
681704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_PRINTER_NAME = "printerName";
682704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_STATE_REASON = "stateReason";
683a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        private static final String ATTR_CANCELLING = "cancelling";
684269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
685b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TAG_ADVANCED_OPTIONS = "advancedOptions";
686b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TAG_ADVANCED_OPTION = "advancedOption";
687b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_KEY = "key";
688b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_TYPE = "type";
689b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String ATTR_VALUE = "value";
690b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TYPE_STRING = "string";
691b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        private static final String TYPE_INT = "int";
692b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
693269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MEDIA_SIZE = "mediaSize";
694269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_RESOLUTION = "resolution";
695269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MARGINS = "margins";
696269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
697269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COLOR_MODE = "colorMode";
698269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
699704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_LOCAL_ID = "localId";
700269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_SERVICE_NAME = "serviceName";
701269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
702269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_WIDTH_MILS = "widthMils";
703269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HEIGHT_MILS = "heightMils";
704269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
705269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HORIZONTAL_DPI = "horizontalDip";
706269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_VERTICAL_DPI = "verticalDpi";
707269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
708269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LEFT_MILS = "leftMils";
709269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TOP_MILS = "topMils";
710269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_RIGHT_MILS = "rightMils";
711269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_BOTTOM_MILS = "bottomMils";
712269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
713269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_START = "start";
714269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_END = "end";
715269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
716269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_NAME = "name";
717269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_PAGE_COUNT = "pageCount";
718269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_CONTENT_TYPE = "contentType";
7197d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov        private static final String ATTR_DATA_SIZE = "dataSize";
720269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
721269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private final AtomicFile mStatePersistFile;
722269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
723269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean mWriteStateScheduled;
724269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
725269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private PersistenceManager() {
726269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mStatePersistFile = new AtomicFile(new File(getFilesDir(),
727269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PERSIST_FILE_NAME));
728269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
729269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
730269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void writeStateLocked() {
7314237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov            if (!PERSISTENCE_MANAGER_ENABLED) {
732269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
733269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
734269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mWriteStateScheduled) {
735269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
736269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
737269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mWriteStateScheduled = true;
738269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            new AsyncTask<Void, Void, Void>() {
739269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                @Override
740269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                protected Void doInBackground(Void... params) {
741269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
742269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mWriteStateScheduled = false;
743269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        doWriteStateLocked();
744269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
745269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return null;
746269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
747269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
748269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
749269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
750269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void doWriteStateLocked() {
751269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
752269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[PERSIST START]");
753269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
754269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileOutputStream out = null;
755269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
756269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                out = mStatePersistFile.startWrite();
757269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
758269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlSerializer serializer = new FastXmlSerializer();
759269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.setOutput(out, "utf-8");
760269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startDocument(null, true);
761269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startTag(null, TAG_SPOOLER);
762269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
763269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                List<PrintJobInfo> printJobs = mPrintJobs;
764269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
765269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int printJobCount = printJobs.size();
766269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                for (int j = 0; j < printJobCount; j++) {
767269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintJobInfo printJob = printJobs.get(j);
768269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
769885810de69d75979df4299d21fa236490767eae4Svetoslav                    if (!shouldPersistPrintJob(printJob)) {
770885810de69d75979df4299d21fa236490767eae4Svetoslav                        continue;
771885810de69d75979df4299d21fa236490767eae4Svetoslav                    }
772885810de69d75979df4299d21fa236490767eae4Svetoslav
773269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.startTag(null, TAG_JOB);
774269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
7752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
776269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
777269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
778269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
779269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String tag = printJob.getTag();
780269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag != null) {
781269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_TAG, tag);
782269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
783704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf(
784704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            printJob.getCreationTime()));
785269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
786704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    String printerName = printJob.getPrinterName();
787704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (!TextUtils.isEmpty(printerName)) {
788704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
789704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
790704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    String stateReason = printJob.getStateReason();
791704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (!TextUtils.isEmpty(stateReason)) {
792704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        serializer.attribute(null, ATTR_STATE_REASON, stateReason);
793704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
794a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    serializer.attribute(null, ATTR_CANCELLING, String.valueOf(
795a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.isCancelling()));
796269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
797269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrinterId printerId = printJob.getPrinterId();
798269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printerId != null) {
799269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_PRINTER_ID);
800269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
801269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
802269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                .flattenToString());
803269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_PRINTER_ID);
804269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
805269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
806269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PageRange[] pages = printJob.getPages();
807269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (pages != null) {
808269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        for (int i = 0; i < pages.length; i++) {
809269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_PAGE_RANGE);
810269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_START, String.valueOf(
811269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getStart()));
812269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_END, String.valueOf(
813269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getEnd()));
814269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_PAGE_RANGE);
815269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
816269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
817269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
818269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintAttributes attributes = printJob.getAttributes();
819269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (attributes != null) {
820269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_ATTRIBUTES);
821269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
822269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int colorMode = attributes.getColorMode();
823269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_COLOR_MODE,
824269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                String.valueOf(colorMode));
825269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
826269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        MediaSize mediaSize = attributes.getMediaSize();
827269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mediaSize != null) {
828269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MEDIA_SIZE);
829269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, mediaSize.getId());
830269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(
831269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getWidthMils()));
832269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf(
833269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getHeightMils()));
834a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // We prefer to store only the package name and
835a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // resource id and fallback to the label.
836a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            if (!TextUtils.isEmpty(mediaSize.mPackageName)
837773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                    && mediaSize.mLabelResId > 0) {
838773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_PACKAGE_NAME,
839773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.mPackageName);
840773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL_RES_ID,
841773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        String.valueOf(mediaSize.mLabelResId));
842773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            } else {
843773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL,
844773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.getLabel(getPackageManager()));
845773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            }
846269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MEDIA_SIZE);
847269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
848269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
849269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Resolution resolution = attributes.getResolution();
850269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (resolution != null) {
851269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_RESOLUTION);
852269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, resolution.getId());
853269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf(
854269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getHorizontalDpi()));
855269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
856269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getVerticalDpi()));
857c6066799ad130140159230d14451b429eb828755Svetoslav                            serializer.attribute(null, ATTR_LABEL,
858651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                                    resolution.getLabel());
859269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_RESOLUTION);
860269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
861269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
862651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        Margins margins = attributes.getMinMargins();
863269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (margins != null) {
864269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MARGINS);
865269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
866269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getLeftMils()));
867269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(
868269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getTopMils()));
869269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(
870269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getRightMils()));
871269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(
872269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getBottomMils()));
873269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MARGINS);
874269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
875269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
876269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_ATTRIBUTES);
877269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
878269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
879269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
880269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (documentInfo != null) {
881269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_DOCUMENT_INFO);
882269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_NAME, documentInfo.getName());
883269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf(
884269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getContentType()));
885269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf(
886269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getPageCount()));
8877d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                        serializer.attribute(null, ATTR_DATA_SIZE, String.valueOf(
8887d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                                documentInfo.getDataSize()));
889269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_DOCUMENT_INFO);
890269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
891269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
892b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    Bundle advancedOptions = printJob.getAdvancedOptions();
893b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    if (advancedOptions != null) {
894b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        serializer.startTag(null, TAG_ADVANCED_OPTIONS);
895b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        for (String key : advancedOptions.keySet()) {
896b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            Object value = advancedOptions.get(key);
897b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            if (value instanceof String) {
898b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                String stringValue = (String) value;
899b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.startTag(null, TAG_ADVANCED_OPTION);
900b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_KEY, key);
901b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_TYPE, TYPE_STRING);
902b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_VALUE, stringValue);
903b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.endTag(null, TAG_ADVANCED_OPTION);
904b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            } else if (value instanceof Integer) {
905b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                String intValue = Integer.toString((Integer) value);
906b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.startTag(null, TAG_ADVANCED_OPTION);
907b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_KEY, key);
908b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_TYPE, TYPE_INT);
909b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.attribute(null, ATTR_VALUE, intValue);
910b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                serializer.endTag(null, TAG_ADVANCED_OPTION);
911b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                            }
912b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        }
913b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        serializer.endTag(null, TAG_ADVANCED_OPTIONS);
914b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    }
915b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
916269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.endTag(null, TAG_JOB);
917269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
918269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (DEBUG_PERSISTENCE) {
919269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Log.i(LOG_TAG, "[PERSISTED] " + printJob);
920269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
921269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
922269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
923269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endTag(null, TAG_SPOOLER);
924269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endDocument();
925269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.finishWrite(out);
926269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PERSISTENCE) {
927269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.i(LOG_TAG, "[PERSIST END]");
928269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
929269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException e) {
930269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
931269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.failWrite(out);
932269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
933269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(out);
934269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
935269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
936269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
937269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void readStateLocked() {
9384237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov            if (!PERSISTENCE_MANAGER_ENABLED) {
939269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
940269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
941269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileInputStream in = null;
942269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
943269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                in = mStatePersistFile.openRead();
944269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (FileNotFoundException e) {
945269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "No existing print spooler state.");
946269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
947269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
948269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
949269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlPullParser parser = Xml.newPullParser();
950269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.setInput(in, null);
951269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parseState(parser);
952269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IllegalStateException ise) {
953269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ise);
954269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NullPointerException npe) {
955269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", npe);
956269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NumberFormatException nfe) {
957269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", nfe);
958269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (XmlPullParserException xppe) {
959269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", xppe);
960269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException ioe) {
961269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ioe);
962269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IndexOutOfBoundsException iobe) {
963269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", iobe);
964269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
965269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(in);
966269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
967269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
968269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
969269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void parseState(XmlPullParser parser)
970269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
971269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
972269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
973269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER);
974269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
975269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
976269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (parsePrintJob(parser)) {
977269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
978269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
979269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
980269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
981269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER);
982269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
983269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
984269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean parsePrintJob(XmlPullParser parser)
985269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
986269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
987269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
988269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
989269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
990269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
991269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = new PrintJobInfo();
992269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
9932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            PrintJobId printJobId = PrintJobId.unflattenFromString(
9942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    parser.getAttributeValue(null, ATTR_ID));
995269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setId(printJobId);
996269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String label = parser.getAttributeValue(null, ATTR_LABEL);
997269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setLabel(label);
998269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
999269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setState(state);
1000269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
1001269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setAppId(appId);
1002269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String tag = parser.getAttributeValue(null, ATTR_TAG);
1003269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setTag(tag);
1004704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
1005704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setCreationTime(Long.parseLong(creationTime));
1006269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String copies = parser.getAttributeValue(null, ATTR_COPIES);
1007269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setCopies(Integer.parseInt(copies));
1008704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
1009704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setPrinterName(printerName);
1010704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
1011704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setStateReason(stateReason);
1012a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
1013a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            printJob.setCancelling(!TextUtils.isEmpty(cancelling)
1014a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    ? Boolean.parseBoolean(cancelling) : false);
1015269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1016269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
1017269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1018269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1019269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
1020269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
1021269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
1022269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        null, ATTR_SERVICE_NAME));
1023269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPrinterId(new PrinterId(service, localId));
1024269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1025269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1026269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
1027269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1028269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1029269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1030269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1031269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            List<PageRange> pageRanges = null;
1032269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
1033269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
1034269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
1035269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange pageRange = new PageRange(start, end);
1036269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (pageRanges == null) {
1037269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    pageRanges = new ArrayList<PageRange>();
1038269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1039269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.add(pageRange);
1040269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1041269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1042269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
1043269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1044b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1045269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1046269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (pageRanges != null) {
1047269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
1048269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.toArray(pageRangesArray);
1049269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPages(pageRangesArray);
1050269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1051269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1052269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1053269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {
1054269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1055269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintAttributes.Builder builder = new PrintAttributes.Builder();
1056269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1057269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
1058269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                builder.setColorMode(Integer.parseInt(colorMode));
1059269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1060269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1061269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1062269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1063269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
1064269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1065269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1066269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int widthMils = Integer.parseInt(parser.getAttributeValue(null,
1067269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_WIDTH_MILS));
1068269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int heightMils = Integer.parseInt(parser.getAttributeValue(null,
1069269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HEIGHT_MILS));
1070773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
1071b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID);
1072b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    final int labelResId = (labelResIdString != null)
1073b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                            ? Integer.parseInt(labelResIdString) : 0;
1074773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1075b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    MediaSize mediaSize = new MediaSize(id, label, packageName,
1076b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                                widthMils, heightMils, labelResId);
1077269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setMediaSize(mediaSize);
1078269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1079269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1080269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
1081269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1082269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1083269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1084269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1085269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
1086269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1087269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1088269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null,
1089269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HORIZONTAL_DPI));
1090269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
1091269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_VERTICAL_DPI));
1092c6066799ad130140159230d14451b429eb828755Svetoslav                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
1093269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setResolution(resolution);
1094269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1095269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1096269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
1097269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1098269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1099269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
1102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int leftMils = Integer.parseInt(parser.getAttributeValue(null,
1103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_LEFT_MILS));
1104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int topMils = Integer.parseInt(parser.getAttributeValue(null,
1105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_TOP_MILS));
1106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int rightMils = Integer.parseInt(parser.getAttributeValue(null,
1107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_RIGHT_MILS));
1108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
1109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_BOTTOM_MILS));
1110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
1111651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                    builder.setMinMargins(margins);
1112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
1115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1116269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1118651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                printJob.setAttributes(builder.build());
1119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
1122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1126269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
1127269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String name = parser.getAttributeValue(null, ATTR_NAME);
1128269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int pageCount = Integer.parseInt(parser.getAttributeValue(null,
1129269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_PAGE_COUNT));
1130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int contentType = Integer.parseInt(parser.getAttributeValue(null,
1131269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_CONTENT_TYPE));
11327d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                final int dataSize = Integer.parseInt(parser.getAttributeValue(null,
11337d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                        ATTR_DATA_SIZE));
1134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintDocumentInfo info = new PrintDocumentInfo.Builder(name)
1135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        .setPageCount(pageCount)
1136651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        .setContentType(contentType).build();
1137269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setDocumentInfo(info);
11387d7888d1c7daa78ee0ad24a24c8dd54b01749259Svetoslav Ganov                info.setDataSize(dataSize);
1139269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1140269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1141269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
1142269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1143269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1144269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1145b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            skipEmptyTextTags(parser);
1146b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTIONS)) {
1147b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                parser.next();
1148b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1149b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                Bundle advancedOptions = new Bundle();
1150b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                while (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTION)) {
1151b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String key = parser.getAttributeValue(null, ATTR_KEY);
1152b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String value = parser.getAttributeValue(null, ATTR_VALUE);
1153b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    String type = parser.getAttributeValue(null, ATTR_TYPE);
1154b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    if (TYPE_STRING.equals(type)) {
1155b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        advancedOptions.putString(key, value);
1156b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    } else if (TYPE_INT.equals(type)) {
1157b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                        advancedOptions.putInt(key, Integer.valueOf(value));
1158b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    }
1159b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    parser.next();
1160b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    skipEmptyTextTags(parser);
1161b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTION);
1162b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    parser.next();
1163b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                    skipEmptyTextTags(parser);
1164b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                }
1165b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                printJob.setAdvancedOptions(advancedOptions);
1166b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                skipEmptyTextTags(parser);
1167b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTIONS);
1168b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                parser.next();
1169b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            }
1170b4fda134761c9521a7e127db3806a07a18763b77Svetoslav
1171269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPrintJobs.add(printJob);
1172269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1173269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
1174269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[RESTORED] " + printJob);
1175269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1176269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1177269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1178269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_JOB);
1179269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1180269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1181269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1182269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1183269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void expect(XmlPullParser parser, int type, String tag)
1184269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1185269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, type, tag)) {
1186269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throw new XmlPullParserException("Exepected event: " + type
1187269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag: " + tag + " but got event: " + parser.getEventType()
1188269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag:" + parser.getName());
1189269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1190269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void skipEmptyTextTags(XmlPullParser parser)
1193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.TEXT, null)
1195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && "\n".equals(parser.getText())) {
1196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1199269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1200269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean accept(XmlPullParser parser, int type, String tag)
1201269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1202269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (parser.getEventType() != type) {
1203269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1204269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1205269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (tag != null) {
1206269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!tag.equals(parser.getName())) {
1207269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
1208269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1209269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } else if (parser.getName() != null) {
1210269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1211269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1212269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1213269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1214269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
12157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
1216a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    public final class PrintSpooler extends IPrintSpooler.Stub {
12177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12187bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
12197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                ComponentName componentName, int state, int appId, int sequence)
12207bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                throws RemoteException {
12217bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            List<PrintJobInfo> printJobs = null;
12227bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJobs = PrintSpoolerService.this.getPrintJobInfos(
12247bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        componentName, state, appId);
12257bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12267bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfosResult(printJobs, sequence);
12277bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12287bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12307bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12317bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
12327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                int appId, int sequence) throws RemoteException {
12337bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintJobInfo printJob = null;
12347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12357bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
12367bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12377bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfoResult(printJob, sequence);
12387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12397bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void createPrintJob(PrintJobInfo printJob) {
12437bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.createPrintJob(printJob);
12447bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12457bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12467bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12477bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobState(PrintJobId printJobId, int state, String error,
12487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
12497bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
12507bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12517bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobState(
12527bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        printJobId, state, error);
12537bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12547bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobStateResult(success, sequece);
12557bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12567bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12577bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12587bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12597bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobTag(PrintJobId printJobId, String tag,
12607bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
12617bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
12627bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12637bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
12647bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12657bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobTagResult(success, sequece);
12667bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12677bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12687bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12697bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12707bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
12717bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.writePrintJobData(fd, printJobId);
12727bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12737bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12747bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12757bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setClient(IPrintSpoolerClient client) {
12767bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
12777bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_SET_CLIENT, client);
12787bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
12797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12807bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void removeObsoletePrintJobs() {
12837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.removeObsoletePrintJobs();
12847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12867bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12877bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
12887bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.dump(fd, writer, args);
12897bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12907bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12917bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12927bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
12937bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
12947bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12957bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12967bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public PrintSpoolerService getService() {
12977bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return PrintSpoolerService.this;
12987bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12997bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    }
13004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
1301