PrintSpoolerService.java revision 9b6d3a153f44010a75907c6a9742c89a57d4e5ee
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
174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage com.android.printspooler;
184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Service;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName;
214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent;
22269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.os.AsyncTask;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.IBinder;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.ParcelFileDescriptor;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException;
27a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpooler;
28a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerCallbacks;
29835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.print.IPrintSpoolerClient;
30269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PageRange;
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintAttributes;
32269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Margins;
33269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.MediaSize;
34269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintAttributes.Resolution;
35269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintDocumentInfo;
362fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo;
38269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrintManager;
39269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrinterId;
40269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrinterInfo;
41a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslavimport android.text.TextUtils;
42dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport android.util.ArrayMap;
43269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.AtomicFile;
44835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.util.Log;
454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Slog;
46269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.util.Xml;
474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
48269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.os.HandlerCaller;
49269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport com.android.internal.util.FastXmlSerializer;
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport libcore.io.IoUtils;
522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
53269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParser;
54269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlPullParserException;
55269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport org.xmlpull.v1.XmlSerializer;
56269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
57269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.File;
58dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.FileDescriptor;
59269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileInputStream;
60269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileNotFoundException;
61269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.FileOutputStream;
62269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.io.IOException;
63dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.io.PrintWriter;
64269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport java.util.ArrayList;
65835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport java.util.List;
66835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Service for exposing some of the {@link PrintSpooler} functionality to
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * another process.
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic final class PrintSpoolerService extends Service {
724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
73269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final String LOG_TAG = "PrintSpoolerService";
74269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
75b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav    private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
76269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
77c6066799ad130140159230d14451b429eb828755Svetoslav    private static final boolean DEBUG_PERSISTENCE = false;
78269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
79269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
80269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
81835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000;
82835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
83dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private static final String PRINT_JOB_FILE_PREFIX = "print_job_";
84dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
85269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final String PRINT_FILE_EXTENSION = "pdf";
86269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
87269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static final Object sLock = new Object();
88269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
89269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final Object mLock = new Object();
90269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
91269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
92269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
93269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private static PrintSpoolerService sInstance;
94269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
95835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private IPrintSpoolerClient mClient;
964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
97269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private HandlerCaller mHandlerCaller;
98269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
99269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private PersistenceManager mPersistanceManager;
100269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private NotificationController mNotificationController;
102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public static PrintSpoolerService peekInstance() {
104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return sInstance;
106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
1084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public void onCreate() {
1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        super.onCreate();
112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller = new HandlerCaller(this, getMainLooper(),
113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                new HandlerCallerCallback(), false);
114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPersistanceManager = new PersistenceManager();
116269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mNotificationController = new NotificationController(PrintSpoolerService.this);
117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPersistanceManager.readStateLocked();
120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            handleReadPrintJobsLocked();
121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (sLock) {
124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            sInstance = this;
125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public IBinder onBind(Intent intent) {
1307bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        return new PrintSpooler();
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
133dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    @Override
134dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
135dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        synchronized (mLock) {
136b67a637e60c356ab520050b2bd09a95ae47f3017Svetoslav            String prefix = (args.length > 0) ? args[0] : "";
137dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            String tab = "  ";
138dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
139dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print jobs:").println();
140dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int printJobCount = mPrintJobs.size();
141dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < printJobCount; i++) {
142dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                PrintJobInfo printJob = mPrintJobs.get(i);
143dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.append(prefix).append(tab).append(printJob.toString());
144dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                pw.println();
145dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
146dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
147dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.append(prefix).append("print job files:").println();
148dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            File[] files = getFilesDir().listFiles();
149dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (files != null) {
150dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int fileCount = files.length;
151dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < fileCount; i++) {
152dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    File file = files[i];
153dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
154dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        pw.append(prefix).append(tab).append(file.getName()).println();
155dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
156dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
157dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
158dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
159dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    }
160dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
161269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnPrintJobQueued(PrintJobInfo printJob) {
162269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
163269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
164269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
165269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
166269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
167269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsForServiceHandled(ComponentName service) {
168269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessageO(
169269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service);
170269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
171269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
172269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
173269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void sendOnAllPrintJobsHandled() {
174269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        Message message = mHandlerCaller.obtainMessage(
175269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED);
176269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mHandlerCaller.executeOrSendMessage(message);
177269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
178269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
179269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class HandlerCallerCallback implements HandlerCaller.Callback {
180704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public static final int MSG_SET_CLIENT = 1;
1817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_QUEUED = 2;
1827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 3;
1837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 4;
1847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 5;
1857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 6;
1864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
188269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void executeMessage(Message message) {
189835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            switch (message.what) {
190835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_SET_CLIENT: {
191269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
192269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mClient = (IPrintSpoolerClient) message.obj;
193269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mClient != null) {
194269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            Message msg = mHandlerCaller.obtainMessage(
195269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED);
196269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            mHandlerCaller.sendMessageDelayed(msg,
197269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    CHECK_ALL_PRINTJOBS_HANDLED_DELAY);
198269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
199835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
200835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
201835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
202835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_PRINT_JOB_QUEUED: {
203835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    PrintJobInfo printJob = (PrintJobInfo) message.obj;
204835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
205835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
206835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onPrintJobQueued(printJob);
207835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
208835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
209835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
210835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
211835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
212835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
213835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: {
214835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    ComponentName service = (ComponentName) message.obj;
215835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
216835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
217835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsForServiceHandled(service);
218835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
219835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print jobs per service"
220835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                    + " handled.", re);
221835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
222835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
223835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
224835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
225835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
226835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    if (mClient != null) {
227835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        try {
228835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            mClient.onAllPrintJobsHandled();
229835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        } catch (RemoteException re) {
230835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
231835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        }
232835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
233835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                } break;
234835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
235835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
236269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    checkAllPrintJobsHandled();
237269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
238704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
239704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                case MSG_ON_PRINT_JOB_STATE_CHANGED: {
240704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (mClient != null) {
241dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        PrintJobInfo printJob = (PrintJobInfo) message.obj;
242704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        try {
243dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            mClient.onPrintJobStateChanged(printJob);
244704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        } catch (RemoteException re) {
245704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            Slog.e(LOG_TAG, "Error notify for print job state change.", re);
246704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        }
247704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
248704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                } break;
2494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
2504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
252269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
253269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName,
254269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            int state, int appId) {
255269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        List<PrintJobInfo> foundPrintJobs = null;
256269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
257269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
258269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
259269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
260269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrinterId printerId = printJob.getPrinterId();
261269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameComponent = (componentName == null
262269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (printerId != null
263269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && componentName.equals(printerId.getServiceName())));
264269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameAppId = appId == PrintManager.APP_ID_ANY
265269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || printJob.getAppId() == appId;
266269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final boolean sameState = (state == printJob.getState())
267269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY)
268269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
269d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                            && isStateVisibleToUser(printJob.getState()))
270d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_ACTIVE
2719b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isActiveState(printJob.getState()))
2729b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                        || (state == PrintJobInfo.STATE_ANY_SCHEDULED
2739b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                            && isScheduledState(printJob.getState()));
274269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (sameComponent && sameAppId && sameState) {
275269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (foundPrintJobs == null) {
276269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        foundPrintJobs = new ArrayList<PrintJobInfo>();
277269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
278269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    foundPrintJobs.add(printJob);
279269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
280269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
281269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
282269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return foundPrintJobs;
283269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
284269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
285d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private boolean isStateVisibleToUser(int state) {
286d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
2872fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
2882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || state == PrintJobInfo.STATE_BLOCKED));
289d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
290d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
2912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
292269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int printJobCount = mPrintJobs.size();
294269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            for (int i = 0; i < printJobCount; i++) {
295269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
2962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (printJob.getId().equals(printJobId)
297269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        && (appId == PrintManager.APP_ID_ANY
298269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        || appId == printJob.getAppId())) {
299269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return printJob;
300269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
301269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
302269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return null;
303269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
304269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
305269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3062fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void createPrintJob(PrintJobInfo printJob) {
307269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
308269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            addPrintJobLocked(printJob);
309dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
3107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
3117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
3127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
3137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    printJob);
3147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
315269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
316269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
317269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
318269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void handleReadPrintJobsLocked() {
319dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Make a map with the files for a print job since we may have
320dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // to delete some. One example of getting orphan files if the
321dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // spooler crashes while constructing a print job. We do not
322dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // persist partially populated print jobs under construction to
323dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // avoid special handling for various attributes missing.
324dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        ArrayMap<PrintJobId, File> fileForJobMap = null;
325dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        File[] files = getFilesDir().listFiles();
326dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (files != null) {
327dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int fileCount = files.length;
328dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < fileCount; i++) {
329dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = files[i];
330dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
331dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (fileForJobMap == null) {
332dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        fileForJobMap = new ArrayMap<PrintJobId, File>();
333dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
3342b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                    String printJobIdString = file.getName().substring(
3352b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            PRINT_JOB_FILE_PREFIX.length(),
3362b40c83ae1ec17ea9371c3fd3ac6c79c156faa1dSvetoslav Ganov                            file.getName().indexOf('.'));
337dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    PrintJobId printJobId = PrintJobId.unflattenFromString(
338dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            printJobIdString);
339dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    fileForJobMap.put(printJobId, file);
340dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
341dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
342dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
343dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
344269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
348dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            // We want to have only the orphan files at the end.
349dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            if (fileForJobMap != null) {
350dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                fileForJobMap.remove(printJob.getId());
351dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
352dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
353269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            switch (printJob.getState()) {
354269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case PrintJobInfo.STATE_QUEUED:
355d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_STARTED:
356d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case PrintJobInfo.STATE_BLOCKED: {
357d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // We have a print job that was queued or started or blocked in
358d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // the past but the device battery died or a crash occurred. In
359d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // this case we assume the print job failed and let the user
360d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    // decide whether to restart the job or just cancel it.
361269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
362269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            getString(R.string.no_connection_to_printer));
3632fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                } break;
364269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
365269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
366dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
367a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        if (!mPrintJobs.isEmpty()) {
368a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            // Update the notification.
369a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            mNotificationController.onUpdateNotifications(mPrintJobs);
370a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
371a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
372dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Delete the orphan files.
373dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (fileForJobMap != null) {
374dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            final int orphanFileCount = fileForJobMap.size();
375dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            for (int i = 0; i < orphanFileCount; i++) {
376dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                File file = fileForJobMap.valueAt(i);
377dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                file.delete();
378dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
379dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
380269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
381269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
382269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public void checkAllPrintJobsHandled() {
383269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
384269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!hasActivePrintJobsLocked()) {
385269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                notifyOnAllPrintJobsHandled();
386269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
387269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
388269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
389269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
391269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final PrintJobInfo printJob;
392269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
393269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
394269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
395269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
396269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
397269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
398269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileInputStream in = null;
399269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                FileOutputStream out = null;
400269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                try {
401269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printJob != null) {
402269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        File file = generateFileForPrintJob(printJobId);
403269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        in = new FileInputStream(file);
404269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out = new FileOutputStream(fd.getFileDescriptor());
405269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
406269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final byte[] buffer = new byte[8192];
407269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    while (true) {
408269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int readByteCount = in.read(buffer);
409269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (readByteCount < 0) {
410269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            return null;
411269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
412269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        out.write(buffer, 0, readByteCount);
413269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
414269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (FileNotFoundException fnfe) {
415269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", fnfe);
416269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } catch (IOException ioe) {
417269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.e(LOG_TAG, "Error writing print job data!", ioe);
418269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } finally {
419269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(in);
420269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(out);
421269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    IoUtils.closeQuietly(fd);
422269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
423269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[END WRITE]");
424269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
425269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
426269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
427269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
428269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4292fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public File generateFileForPrintJob(PrintJobId printJobId) {
430dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        return new File(getFilesDir(), PRINT_JOB_FILE_PREFIX
4312fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
432269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
433269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
434269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void addPrintJobLocked(PrintJobInfo printJob) {
435269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        mPrintJobs.add(printJob);
436269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (DEBUG_PRINT_JOB_LIFECYCLE) {
437269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            Slog.i(LOG_TAG, "[ADD] " + printJob);
438269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
439269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4412fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removeObsoletePrintJobs() {
4422fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        synchronized (mLock) {
4432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            final int printJobCount = mPrintJobs.size();
4442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            for (int i = printJobCount - 1; i >= 0; i--) {
4452fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                PrintJobInfo printJob = mPrintJobs.get(i);
4462fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                if (isObsoleteState(printJob.getState())) {
4472fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    mPrintJobs.remove(i);
4482fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    if (DEBUG_PRINT_JOB_LIFECYCLE) {
4492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
4502fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    }
4512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    removePrintJobFileLocked(printJob.getId());
4522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                }
4532fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
4542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            mPersistanceManager.writeStateLocked();
4552fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
4562fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
4572fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
4582fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private void removePrintJobFileLocked(PrintJobId printJobId) {
4592fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        File file = generateFileForPrintJob(printJobId);
4602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (file.exists()) {
4612fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            file.delete();
462269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PRINT_JOB_LIFECYCLE) {
463dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
464269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
465269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
466269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
467269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
4682fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
469269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        boolean success = false;
470269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
471269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
472269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
473269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
474704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final int oldState = printJob.getState();
475704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                if (oldState == state) {
476704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    return false;
477704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
478704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
479269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                success = true;
480269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
481269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setState(state);
482d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                printJob.setStateReason(error);
483a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(false);
484269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
485269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PRINT_JOB_LIFECYCLE) {
486269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
487269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
488269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
489269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                switch (state) {
490269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_COMPLETED:
491269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_CANCELED:
492dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        mPrintJobs.remove(printJob);
4932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        removePrintJobFileLocked(printJob.getId());
494269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        // $fall-through$
495269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
496269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_FAILED: {
497269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        PrinterId printerId = printJob.getPrinterId();
498269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (printerId != null) {
499269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ComponentName service = printerId.getServiceName();
500269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            if (!hasActivePrintJobsForServiceLocked(service)) {
501269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                sendOnAllPrintJobsForServiceHandled(service);
502269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            }
503269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
504269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    } break;
505269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
506269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    case PrintJobInfo.STATE_QUEUED: {
507269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        sendOnPrintJobQueued(new PrintJobInfo(printJob));
508269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }  break;
509269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
510269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
511269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
512269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
513269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
514269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
515269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!hasActivePrintJobsLocked()) {
516269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    notifyOnAllPrintJobsHandled();
517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
518704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
519dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                Message message = mHandlerCaller.obtainMessageO(
520704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
521dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJob);
522704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                mHandlerCaller.executeOrSendMessage(message);
523a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
524a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mNotificationController.onUpdateNotifications(mPrintJobs);
525269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
526269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
527269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
528269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return success;
529269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
530269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
531269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsLocked() {
532269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
533269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
534269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
535269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (isActiveState(printJob.getState())) {
536269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
537269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
538269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
539269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
540269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
541269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
542269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    public boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
543269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        final int printJobCount = mPrintJobs.size();
544269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        for (int i = 0; i < printJobCount; i++) {
545269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = mPrintJobs.get(i);
546269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (isActiveState(printJob.getState())
547269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && printJob.getPrinterId().getServiceName().equals(service)) {
548269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
549269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
550269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
551269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
552269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
553269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
5542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private boolean isObsoleteState(int printJobState) {
5552fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        return (isTeminalState(printJobState)
5562fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED);
5572fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
5582fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
5599b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    private boolean isScheduledState(int printJobState) {
5609b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov        return printJobState == PrintJobInfo.STATE_QUEUED
5619b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
5629b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
5639b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    }
5649b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov
565269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean isActiveState(int printJobState) {
566269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJobState == PrintJobInfo.STATE_CREATED
567269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                || printJobState == PrintJobInfo.STATE_QUEUED
568d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_STARTED
569d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                || printJobState == PrintJobInfo.STATE_BLOCKED;
570269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
571269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
5722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private boolean isTeminalState(int printJobState) {
5732fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        return printJobState == PrintJobInfo.STATE_COMPLETED
5742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                || printJobState == PrintJobInfo.STATE_CANCELED;
5752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
5762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
5772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
578269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
579269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
580269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
581269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String printJobTag = printJob.getTag();
582269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (printJobTag == null) {
583269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag == null) {
584269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        return false;
585269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
586269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } else if (printJobTag.equals(tag)) {
587269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
588269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
589269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setTag(tag);
590269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (shouldPersistPrintJob(printJob)) {
591269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mPersistanceManager.writeStateLocked();
592269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
593269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return true;
594269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
595269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
596269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return false;
597269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
598269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
599a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
600a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        synchronized (mLock) {
601a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
602a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (printJob != null) {
603a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJob.setCancelling(cancelling);
604a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (shouldPersistPrintJob(printJob)) {
605a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    mPersistanceManager.writeStateLocked();
606a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
607a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mNotificationController.onUpdateNotifications(mPrintJobs);
608a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
609a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                Message message = mHandlerCaller.obtainMessageO(
610a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
611a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        printJob);
612a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mHandlerCaller.executeOrSendMessage(message);
613a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
614a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
615a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
616a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
6172fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
618269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
619269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
620269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
621269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setCopies(copies);
622269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
623269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
624269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
625269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
6262fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId,
6272fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            PrintDocumentInfo info) {
628269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
629269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
630269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
631269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setDocumentInfo(info);
632269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
633269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
634269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
635269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
6362fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void setPrintJobAttributesNoPersistence(PrintJobId printJobId,
6372fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            PrintAttributes attributes) {
638269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
639269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
640269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
641269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setAttributes(attributes);
642269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
643269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
644269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
645269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
6462fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void setPrintJobPrinterNoPersistence(PrintJobId printJobId, PrinterInfo printer) {
647269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
648269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
649269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
650269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPrinterId(printer.getId());
651269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPrinterName(printer.getName());
652269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
653269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
654269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
655269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
6562fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void setPrintJobPagesNoPersistence(PrintJobId printJobId, PageRange[] pages) {
657269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
658269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
659269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (printJob != null) {
660269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPages(pages);
661269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
662269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
663269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
664269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
665269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
666269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
667269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
668269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
669269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private void notifyOnAllPrintJobsHandled() {
670269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // This has to run on the tread that is persisting the current state
671269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // since this call may result in the system unbinding from the spooler
672269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // and as a result the spooler process may get killed before the write
673269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        // completes.
674269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        new AsyncTask<Void, Void, Void>() {
675269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
676269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            protected Void doInBackground(Void... params) {
677269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                sendOnAllPrintJobsHandled();
678269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return null;
679269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
680269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
681269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
682269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
683269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private final class PersistenceManager {
684269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
685269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
686269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_SPOOLER = "spooler";
687269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_JOB = "job";
688269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
689269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PRINTER_ID = "printerId";
690269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_PAGE_RANGE = "pageRange";
691269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_ATTRIBUTES = "attributes";
692269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_DOCUMENT_INFO = "documentInfo";
693269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
694269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_ID = "id";
695269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LABEL = "label";
696773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_LABEL_RES_ID = "labelResId";
697773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav        private static final String ATTR_PACKAGE_NAME = "packageName";
698269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_STATE = "state";
699269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_APP_ID = "appId";
700269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TAG = "tag";
701704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_CREATION_TIME = "creationTime";
702269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COPIES = "copies";
703704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_PRINTER_NAME = "printerName";
704704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_STATE_REASON = "stateReason";
705a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        private static final String ATTR_CANCELLING = "cancelling";
706269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
707269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MEDIA_SIZE = "mediaSize";
708269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_RESOLUTION = "resolution";
709269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String TAG_MARGINS = "margins";
710269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
711269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_COLOR_MODE = "colorMode";
712269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
713704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        private static final String ATTR_LOCAL_ID = "localId";
714269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_SERVICE_NAME = "serviceName";
715269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
716269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_WIDTH_MILS = "widthMils";
717269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HEIGHT_MILS = "heightMils";
718269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
719269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_HORIZONTAL_DPI = "horizontalDip";
720269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_VERTICAL_DPI = "verticalDpi";
721269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
722269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_LEFT_MILS = "leftMils";
723269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_TOP_MILS = "topMils";
724269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_RIGHT_MILS = "rightMils";
725269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_BOTTOM_MILS = "bottomMils";
726269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
727269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_START = "start";
728269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_END = "end";
729269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
730269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_NAME = "name";
731269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_PAGE_COUNT = "pageCount";
732269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private static final String ATTR_CONTENT_TYPE = "contentType";
733269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
734269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private final AtomicFile mStatePersistFile;
735269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
736269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean mWriteStateScheduled;
737269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
738269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private PersistenceManager() {
739269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mStatePersistFile = new AtomicFile(new File(getFilesDir(),
740269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PERSIST_FILE_NAME));
741269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
742269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
743269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void writeStateLocked() {
744269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!PERSISTNECE_MANAGER_ENABLED) {
745269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
746269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
747269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mWriteStateScheduled) {
748269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
749269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
750269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mWriteStateScheduled = true;
751269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            new AsyncTask<Void, Void, Void>() {
752269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                @Override
753269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                protected Void doInBackground(Void... params) {
754269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    synchronized (mLock) {
755269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mWriteStateScheduled = false;
756269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        doWriteStateLocked();
757269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
758269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return null;
759269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
760269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
761269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
762269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
763269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void doWriteStateLocked() {
764269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
765269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[PERSIST START]");
766269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
767269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileOutputStream out = null;
768269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
769269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                out = mStatePersistFile.startWrite();
770269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
771269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlSerializer serializer = new FastXmlSerializer();
772269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.setOutput(out, "utf-8");
773269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startDocument(null, true);
774269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.startTag(null, TAG_SPOOLER);
775269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
776269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                List<PrintJobInfo> printJobs = mPrintJobs;
777269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
778269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int printJobCount = printJobs.size();
779269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                for (int j = 0; j < printJobCount; j++) {
780269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintJobInfo printJob = printJobs.get(j);
781269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
782269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.startTag(null, TAG_JOB);
783269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
7842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
785269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
786269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
787269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
788269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String tag = printJob.getTag();
789269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (tag != null) {
790269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_TAG, tag);
791269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
792704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf(
793704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                            printJob.getCreationTime()));
794269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
795704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    String printerName = printJob.getPrinterName();
796704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (!TextUtils.isEmpty(printerName)) {
797704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
798704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
799704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    String stateReason = printJob.getStateReason();
800704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    if (!TextUtils.isEmpty(stateReason)) {
801704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        serializer.attribute(null, ATTR_STATE_REASON, stateReason);
802704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    }
803a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    serializer.attribute(null, ATTR_CANCELLING, String.valueOf(
804a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.isCancelling()));
805269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
806269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrinterId printerId = printJob.getPrinterId();
807269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (printerId != null) {
808269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_PRINTER_ID);
809269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
810269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
811269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                .flattenToString());
812269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_PRINTER_ID);
813269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
814269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
815269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PageRange[] pages = printJob.getPages();
816269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (pages != null) {
817269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        for (int i = 0; i < pages.length; i++) {
818269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_PAGE_RANGE);
819269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_START, String.valueOf(
820269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getStart()));
821269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_END, String.valueOf(
822269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    pages[i].getEnd()));
823269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_PAGE_RANGE);
824269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
825269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
826269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
827269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintAttributes attributes = printJob.getAttributes();
828269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (attributes != null) {
829269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_ATTRIBUTES);
830269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
831269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        final int colorMode = attributes.getColorMode();
832269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_COLOR_MODE,
833269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                String.valueOf(colorMode));
834269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
835269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        MediaSize mediaSize = attributes.getMediaSize();
836269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (mediaSize != null) {
837269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MEDIA_SIZE);
838269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, mediaSize.getId());
839269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(
840269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getWidthMils()));
841269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf(
842269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    mediaSize.getHeightMils()));
843a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // We prefer to store only the package name and
844a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            // resource id and fallback to the label.
845a76233ae845da4bc9e3bcd89821701a747215e7bSvetoslav                            if (!TextUtils.isEmpty(mediaSize.mPackageName)
846773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                    && mediaSize.mLabelResId > 0) {
847773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_PACKAGE_NAME,
848773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.mPackageName);
849773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL_RES_ID,
850773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        String.valueOf(mediaSize.mLabelResId));
851773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            } else {
852773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                serializer.attribute(null, ATTR_LABEL,
853773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                        mediaSize.getLabel(getPackageManager()));
854773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                            }
855269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MEDIA_SIZE);
856269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
857269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
858269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Resolution resolution = attributes.getResolution();
859269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (resolution != null) {
860269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_RESOLUTION);
861269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_ID, resolution.getId());
862269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf(
863269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getHorizontalDpi()));
864269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
865269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    resolution.getVerticalDpi()));
866c6066799ad130140159230d14451b429eb828755Svetoslav                            serializer.attribute(null, ATTR_LABEL,
867651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                                    resolution.getLabel());
868269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_RESOLUTION);
869269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
870269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
871651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        Margins margins = attributes.getMinMargins();
872269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        if (margins != null) {
873269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.startTag(null, TAG_MARGINS);
874269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
875269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getLeftMils()));
876269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(
877269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getTopMils()));
878269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(
879269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getRightMils()));
880269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(
881269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                    margins.getBottomMils()));
882269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            serializer.endTag(null, TAG_MARGINS);
883269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        }
884269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
885269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_ATTRIBUTES);
886269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
887269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
888269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
889269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (documentInfo != null) {
890269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.startTag(null, TAG_DOCUMENT_INFO);
891269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_NAME, documentInfo.getName());
892269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf(
893269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getContentType()));
894269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf(
895269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                                documentInfo.getPageCount()));
896269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        serializer.endTag(null, TAG_DOCUMENT_INFO);
897269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
898269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
899269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    serializer.endTag(null, TAG_JOB);
900269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
901269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (DEBUG_PERSISTENCE) {
902269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        Log.i(LOG_TAG, "[PERSISTED] " + printJob);
903269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
904269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
905269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
906269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endTag(null, TAG_SPOOLER);
907269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                serializer.endDocument();
908269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.finishWrite(out);
909269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (DEBUG_PERSISTENCE) {
910269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Log.i(LOG_TAG, "[PERSIST END]");
911269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
912269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException e) {
913269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
914269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mStatePersistFile.failWrite(out);
915269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
916269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(out);
917269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
918269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
919269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
920269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public void readStateLocked() {
921269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!PERSISTNECE_MANAGER_ENABLED) {
922269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
923269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
924269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            FileInputStream in = null;
925269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
926269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                in = mStatePersistFile.openRead();
927269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (FileNotFoundException e) {
928269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "No existing print spooler state.");
929269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
930269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
931269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            try {
932269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                XmlPullParser parser = Xml.newPullParser();
933269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.setInput(in, null);
934269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parseState(parser);
935269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IllegalStateException ise) {
936269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ise);
937269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NullPointerException npe) {
938269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", npe);
939269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (NumberFormatException nfe) {
940269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", nfe);
941269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (XmlPullParserException xppe) {
942269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", xppe);
943269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IOException ioe) {
944269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", ioe);
945269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } catch (IndexOutOfBoundsException iobe) {
946269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Slog.w(LOG_TAG, "Failed parsing ", iobe);
947269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } finally {
948269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                IoUtils.closeQuietly(in);
949269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
950269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
951269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
952269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void parseState(XmlPullParser parser)
953269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
954269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
955269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
956269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER);
957269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
958269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
959269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (parsePrintJob(parser)) {
960269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
961269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
962269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
963269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
964269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER);
965269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
966269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
967269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean parsePrintJob(XmlPullParser parser)
968269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
969269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
970269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
971269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
972269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
973269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
974269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            PrintJobInfo printJob = new PrintJobInfo();
975269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
9762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            PrintJobId printJobId = PrintJobId.unflattenFromString(
9772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    parser.getAttributeValue(null, ATTR_ID));
978269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setId(printJobId);
979269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String label = parser.getAttributeValue(null, ATTR_LABEL);
980269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setLabel(label);
981269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
982269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setState(state);
983269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
984269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setAppId(appId);
985269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String tag = parser.getAttributeValue(null, ATTR_TAG);
986269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setTag(tag);
987704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
988704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setCreationTime(Long.parseLong(creationTime));
989269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            String copies = parser.getAttributeValue(null, ATTR_COPIES);
990269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            printJob.setCopies(Integer.parseInt(copies));
991704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
992704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setPrinterName(printerName);
993704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
994704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            printJob.setStateReason(stateReason);
995a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
996a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            printJob.setCancelling(!TextUtils.isEmpty(cancelling)
997a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    ? Boolean.parseBoolean(cancelling) : false);
998269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
999269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            parser.next();
1000269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1001269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1002269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
1003269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
1004269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
1005269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        null, ATTR_SERVICE_NAME));
1006269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPrinterId(new PrinterId(service, localId));
1007269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1008269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1009269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
1010269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1011269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1012269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1013269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1014269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            List<PageRange> pageRanges = null;
1015269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
1016269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
1017269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
1018269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange pageRange = new PageRange(start, end);
1019269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (pageRanges == null) {
1020269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    pageRanges = new ArrayList<PageRange>();
1021269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1022269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.add(pageRange);
1023269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1024269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1025269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
1026269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1027269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1028269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (pageRanges != null) {
1029269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
1030269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                pageRanges.toArray(pageRangesArray);
1031269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setPages(pageRangesArray);
1032269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1033269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1034269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1035269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {
1036269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1037269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintAttributes.Builder builder = new PrintAttributes.Builder();
1038269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1039269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
1040269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                builder.setColorMode(Integer.parseInt(colorMode));
1041269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1042269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1043269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1044269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1045269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
1046269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1047269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1048269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int widthMils = Integer.parseInt(parser.getAttributeValue(null,
1049269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_WIDTH_MILS));
1050269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int heightMils = Integer.parseInt(parser.getAttributeValue(null,
1051269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HEIGHT_MILS));
1052773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
1053b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID);
1054b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                    final int labelResId = (labelResIdString != null)
1055b206f1271d17164c3f2f65219eee7a0b4b4fa6dcSvetoslav                            ? Integer.parseInt(labelResIdString) : 0;
1056773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1057773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                    MediaSize mediaSize = new MediaSize(id, label, packageName, labelResId,
1058773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                                widthMils, heightMils);
1059269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setMediaSize(mediaSize);
1060269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1061269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1062269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
1063269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1064269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1065269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1066269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1067269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
1068269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    String id = parser.getAttributeValue(null, ATTR_ID);
1069269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    label = parser.getAttributeValue(null, ATTR_LABEL);
1070269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null,
1071269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_HORIZONTAL_DPI));
1072269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
1073269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_VERTICAL_DPI));
1074c6066799ad130140159230d14451b429eb828755Svetoslav                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
1075269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    builder.setResolution(resolution);
1076269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1077269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1078269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
1079269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1080269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1081269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1082269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1083269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
1084269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int leftMils = Integer.parseInt(parser.getAttributeValue(null,
1085269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_LEFT_MILS));
1086269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int topMils = Integer.parseInt(parser.getAttributeValue(null,
1087269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_TOP_MILS));
1088269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int rightMils = Integer.parseInt(parser.getAttributeValue(null,
1089269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_RIGHT_MILS));
1090269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
1091269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                            ATTR_BOTTOM_MILS));
1092269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
1093651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                    builder.setMinMargins(margins);
1094269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1095269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    skipEmptyTextTags(parser);
1096269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
1097269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    parser.next();
1098269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1099269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1100651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                printJob.setAttributes(builder.build());
1101269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1102269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1103269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
1104269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1105269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1106269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1107269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1108269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
1109269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                String name = parser.getAttributeValue(null, ATTR_NAME);
1110269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int pageCount = Integer.parseInt(parser.getAttributeValue(null,
1111269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_PAGE_COUNT));
1112269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                final int contentType = Integer.parseInt(parser.getAttributeValue(null,
1113269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        ATTR_CONTENT_TYPE));
1114269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                PrintDocumentInfo info = new PrintDocumentInfo.Builder(name)
1115269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        .setPageCount(pageCount)
1116651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav                        .setContentType(contentType).build();
1117269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                printJob.setDocumentInfo(info);
1118269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1119269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                skipEmptyTextTags(parser);
1120269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
1121269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1122269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1123269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1124269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            mPrintJobs.add(printJob);
1125269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1126269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (DEBUG_PERSISTENCE) {
1127269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                Log.i(LOG_TAG, "[RESTORED] " + printJob);
1128269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1129269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1130269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            skipEmptyTextTags(parser);
1131269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            expect(parser, XmlPullParser.END_TAG, TAG_JOB);
1132269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1133269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1134269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1135269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1136269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void expect(XmlPullParser parser, int type, String tag)
1137269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1138269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (!accept(parser, type, tag)) {
1139269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throw new XmlPullParserException("Exepected event: " + type
1140269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag: " + tag + " but got event: " + parser.getEventType()
1141269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        + " and tag:" + parser.getName());
1142269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1143269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1144269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1145269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private void skipEmptyTextTags(XmlPullParser parser)
1146269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1147269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            while (accept(parser, XmlPullParser.TEXT, null)
1148269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    && "\n".equals(parser.getText())) {
1149269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                parser.next();
1150269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1151269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1152269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
1153269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        private boolean accept(XmlPullParser parser, int type, String tag)
1154269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                throws IOException, XmlPullParserException {
1155269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (parser.getEventType() != type) {
1156269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1157269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1158269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (tag != null) {
1159269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                if (!tag.equals(parser.getName())) {
1160269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    return false;
1161269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                }
1162269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            } else if (parser.getName() != null) {
1163269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return false;
1164269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
1165269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            return true;
1166269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
1167269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
11687bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
11697bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    final class PrintSpooler extends IPrintSpooler.Stub {
11707bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
11717bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
11727bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                ComponentName componentName, int state, int appId, int sequence)
11737bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                throws RemoteException {
11747bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            List<PrintJobInfo> printJobs = null;
11757bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
11767bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJobs = PrintSpoolerService.this.getPrintJobInfos(
11777bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        componentName, state, appId);
11787bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
11797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfosResult(printJobs, sequence);
11807bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
11817bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
11827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
11837bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
11847bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
11857bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                int appId, int sequence) throws RemoteException {
11867bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintJobInfo printJob = null;
11877bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
11887bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
11897bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
11907bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onGetPrintJobInfoResult(printJob, sequence);
11917bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
11927bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
11937bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
11947bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
11957bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void createPrintJob(PrintJobInfo printJob) {
11967bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.createPrintJob(printJob);
11977bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
11987bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
11997bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobState(PrintJobId printJobId, int state, String error,
12017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
12027bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
12037bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobState(
12057bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                        printJobId, state, error);
12067bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12077bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobStateResult(success, sequece);
12087bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12097bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobTag(PrintJobId printJobId, String tag,
12137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
12147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            boolean success = false;
12157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            try {
12167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
12177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            } finally {
12187bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                callback.onSetPrintJobTagResult(success, sequece);
12197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
12207bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12217bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12227bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
12247bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.writePrintJobData(fd, printJobId);
12257bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12267bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12277bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12287bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setClient(IPrintSpoolerClient client) {
12297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Message message = mHandlerCaller.obtainMessageO(
12307bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    HandlerCallerCallback.MSG_SET_CLIENT, client);
12317bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            mHandlerCaller.executeOrSendMessage(message);
12327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12337bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12357bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void removeObsoletePrintJobs() {
12367bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.removeObsoletePrintJobs();
12377bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12397bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
12417bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.dump(fd, writer, args);
12427bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12437bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12447bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
12457bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
12467bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
12477bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
12497bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public PrintSpoolerService getService() {
12507bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return PrintSpoolerService.this;
12517bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
12527bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    }
12534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
1254