1a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov/*
2a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
3a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov *
4a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
5a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * you may not use this file except in compliance with the License.
6a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * You may obtain a copy of the License at
7a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov *
8a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
9a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov *
10a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software
11a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
12a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * See the License for the specific language governing permissions and
14a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * limitations under the License.
15a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov */
16a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
17a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovpackage com.android.server.print;
18a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.app.PendingIntent;
20a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.ComponentName;
21a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.Context;
22a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.Intent;
237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.content.IntentSender;
24d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganovimport android.content.pm.ApplicationInfo;
25a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.pm.PackageManager;
262fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.content.pm.ParceledListSlice;
27a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.pm.ResolveInfo;
28d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganovimport android.content.pm.ServiceInfo;
297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.net.Uri;
30c6066799ad130140159230d14451b429eb828755Svetoslavimport android.os.AsyncTask;
31c6066799ad130140159230d14451b429eb828755Svetoslavimport android.os.Binder;
327bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.os.Bundle;
3344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Handler;
3444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.IBinder;
352fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.os.IBinder.DeathRecipient;
3644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Looper;
3744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.Message;
3844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.RemoteCallbackList;
3944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.os.RemoteException;
404a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganovimport android.os.UserHandle;
412fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.IPrintDocumentAdapter;
42704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganovimport android.print.IPrintJobStateChangeListener;
4344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.print.IPrinterDiscoveryObserver;
442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintAttributes;
452fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
46a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.PrintJobInfo;
47c6066799ad130140159230d14451b429eb828755Svetoslavimport android.print.PrintManager;
48269403b032f965ff3847eb982c2f697229dc5a92Svetoslavimport android.print.PrinterId;
4944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.print.PrinterInfo;
50a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.printservice.PrintServiceInfo;
517bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.provider.DocumentsContract;
52a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.provider.Settings;
53a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.text.TextUtils;
54a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.text.TextUtils.SimpleStringSplitter;
5544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.ArrayMap;
56b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport android.util.ArraySet;
5744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.util.Log;
58a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.Slog;
59dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport android.util.SparseArray;
60a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
61c6066799ad130140159230d14451b429eb828755Svetoslavimport com.android.internal.R;
622fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport com.android.internal.os.BackgroundThread;
6344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport com.android.internal.os.SomeArgs;
64c6066799ad130140159230d14451b429eb828755Svetoslavimport com.android.server.print.RemotePrintService.PrintServiceCallbacks;
65a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
66a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
67b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.FileDescriptor;
68b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.PrintWriter;
69a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.ArrayList;
70dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganovimport java.util.Collections;
71a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.HashSet;
72d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganovimport java.util.Iterator;
73a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.List;
74dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslavimport java.util.Map;
75a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.Set;
76a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
77a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov/**
78a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * Represents the print state for a user.
79a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov */
80c6066799ad130140159230d14451b429eb828755Svetoslavfinal class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
81a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final String LOG_TAG = "UserState";
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
84c6066799ad130140159230d14451b429eb828755Svetoslav    private static final boolean DEBUG = false;
8544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
86a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final char COMPONENT_NAME_SEPARATOR = ':';
87a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
88a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SimpleStringSplitter mStringColonSplitter =
89a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
91a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Intent mQueryIntent =
92a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
93a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
94b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    private final ArrayMap<ComponentName, RemotePrintService> mActiveServices =
95b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            new ArrayMap<ComponentName, RemotePrintService>();
96a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
97a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final List<PrintServiceInfo> mInstalledServices =
98a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            new ArrayList<PrintServiceInfo>();
99a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
100a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Set<ComponentName> mEnabledServices =
101b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            new ArraySet<ComponentName>();
102a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
103dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private final PrintJobForAppCache mPrintJobForAppCache =
104dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            new PrintJobForAppCache();
1052fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
106a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Object mLock;
107a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
108a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Context mContext;
109a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
110a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final int mUserId;
111a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
112a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final RemotePrintSpooler mSpooler;
113a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
114704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private final Handler mHandler;
115704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
11644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private PrinterDiscoverySessionMediator mPrinterDiscoverySession;
11744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
118704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
119704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
120a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean mDestroyed;
121a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
122a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public UserState(Context context, int userId, Object lock) {
123a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mContext = context;
124a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mUserId = userId;
125a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mLock = lock;
126a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mSpooler = new RemotePrintSpooler(context, userId, this);
127704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        mHandler = new UserStateHandler(context.getMainLooper());
1286bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        synchronized (mLock) {
129564560e46d8a075fe508514f3dbd94f29963e6ebSvetoslav            enableSystemPrintServicesLocked();
130564560e46d8a075fe508514f3dbd94f29963e6ebSvetoslav            onConfigurationChangedLocked();
1316bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        }
132a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
133a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
134a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    @Override
135a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void onPrintJobQueued(PrintJobInfo printJob) {
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final RemotePrintService service;
137a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
138a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
1398c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            ComponentName printServiceName = printJob.getPrinterId().getServiceName();
140a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            service = mActiveServices.get(printServiceName);
141a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
142a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (service != null) {
143a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            service.onPrintJobQueued(printJob);
144db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov        } else {
145db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov            // The service for the job is no longer enabled, so just
146db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov            // fail the job with the appropriate message.
147db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov            mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
148db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov                    mContext.getString(R.string.reason_service_unavailable));
149a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
150a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
151a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
152a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    @Override
153a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void onAllPrintJobsForServiceHandled(ComponentName printService) {
154a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final RemotePrintService service;
155a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            service = mActiveServices.get(printService);
158a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
159a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (service != null) {
160a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            service.onAllPrintJobsHandled();
161a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
162a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
163a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1642fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void removeObsoletePrintJobs() {
1652fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        mSpooler.removeObsoletePrintJobs();
1662fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
1672fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
1687bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    @SuppressWarnings("deprecation")
1697bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
1707bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintAttributes attributes, String packageName, int appId) {
1712fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        // Create print job place holder.
1722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        final PrintJobInfo printJob = new PrintJobInfo();
173dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        printJob.setId(new PrintJobId());
1742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        printJob.setAppId(appId);
1752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        printJob.setLabel(printJobName);
1762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        printJob.setAttributes(attributes);
1772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        printJob.setState(PrintJobInfo.STATE_CREATED);
178704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        printJob.setCopies(1);
1797bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        printJob.setCreationTime(System.currentTimeMillis());
1802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
181dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Track this job so we can forget it when the creator dies.
1827bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        if (!mPrintJobForAppCache.onPrintJobCreated(adapter.asBinder(), appId,
183dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                printJob)) {
184dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            // Not adding a print job means the client is dead - done.
185dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            return null;
186dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
187dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
1882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        // Spin the spooler to add the job and show the config UI.
1892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        new AsyncTask<Void, Void, Void>() {
1902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            @Override
1912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            protected Void doInBackground(Void... params) {
1927bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                mSpooler.createPrintJob(printJob);
1932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                return null;
1942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
1952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
1962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
1977bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        final long identity = Binder.clearCallingIdentity();
1987bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        try {
1997bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Intent intent = new Intent(PrintManager.ACTION_PRINT_DIALOG);
2007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            intent.setData(Uri.fromParts("printjob", printJob.getId().flattenToString(), null));
2017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            intent.putExtra(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER, adapter.asBinder());
2027bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            intent.putExtra(PrintManager.EXTRA_PRINT_JOB, printJob);
2037bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, packageName);
2047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
2054a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov            IntentSender intentSender = PendingIntent.getActivityAsUser(
2067bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
207b0a78390ed834724e9c6adf0feff9931d7f9ec10Svetoslav                    | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
208b0a78390ed834724e9c6adf0feff9931d7f9ec10Svetoslav                    null, new UserHandle(mUserId)) .getIntentSender();
2097bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
2107bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Bundle result = new Bundle();
2117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            result.putParcelable(PrintManager.EXTRA_PRINT_JOB, printJob);
2127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            result.putParcelable(PrintManager.EXTRA_PRINT_DIALOG_INTENT, intentSender);
2137bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
2147bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return result;
2157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        } finally {
2167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            Binder.restoreCallingIdentity(identity);
2177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
2182fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
2192fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
2202fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public List<PrintJobInfo> getPrintJobInfos(int appId) {
221dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        List<PrintJobInfo> cachedPrintJobs = mPrintJobForAppCache.getPrintJobs(appId);
222dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Note that the print spooler is not storing print jobs that
223dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // are in a terminal state as it is non-trivial to properly update
224dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // the spooler state for when to forget print jobs in terminal state.
225dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Therefore, we fuse the cached print jobs for running apps (some
226dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // jobs are in a terminal state) with the ones that the print
227dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // spooler knows about (some jobs are being processed).
228dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        ArrayMap<PrintJobId, PrintJobInfo> result =
229dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                new ArrayMap<PrintJobId, PrintJobInfo>();
230dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
231dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Add the cached print jobs for running apps.
232dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        final int cachedPrintJobCount = cachedPrintJobs.size();
233dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        for (int i = 0; i < cachedPrintJobCount; i++) {
234dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            PrintJobInfo cachedPrintJob = cachedPrintJobs.get(i);
235dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            result.put(cachedPrintJob.getId(), cachedPrintJob);
236b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            // Strip out the tag and the advanced print options.
237b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            // They are visible only to print services.
238b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav            cachedPrintJob.setTag(null);
239b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            cachedPrintJob.setAdvancedOptions(null);
240dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
241dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
242dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        // Add everything else the spooler knows about.
243dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(null,
244dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                PrintJobInfo.STATE_ANY, appId);
245d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        if (printJobs != null) {
246d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            final int printJobCount = printJobs.size();
247d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            for (int i = 0; i < printJobCount; i++) {
248d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav                PrintJobInfo printJob = printJobs.get(i);
249d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav                result.put(printJob.getId(), printJob);
250b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                // Strip out the tag and the advanced print options.
251b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                // They are visible only to print services.
252b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav                printJob.setTag(null);
253b4fda134761c9521a7e127db3806a07a18763b77Svetoslav                printJob.setAdvancedOptions(null);
254d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            }
255dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
256dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
257dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        return new ArrayList<PrintJobInfo>(result.values());
2582fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
2592fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
2602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
261dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
262b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        if (printJob == null) {
263b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            printJob = mSpooler.getPrintJobInfo(printJobId, appId);
264b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        }
265dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        if (printJob != null) {
266b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            // Strip out the tag and the advanced print options.
267b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            // They are visible only to print services.
268b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            printJob.setTag(null);
269b4fda134761c9521a7e127db3806a07a18763b77Svetoslav            printJob.setAdvancedOptions(null);
270dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
271b4fda134761c9521a7e127db3806a07a18763b77Svetoslav        return printJob;
2722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
2732fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
2742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void cancelPrintJob(PrintJobId printJobId, int appId) {
2752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
2762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (printJobInfo == null) {
2772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
2782fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
279a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
280a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        // Take a note that we are trying to cancel the job.
281a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mSpooler.setPrintJobCancelling(printJobId, true);
282a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
2832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
2842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
2852fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            RemotePrintService printService = null;
2862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            synchronized (mLock) {
2872fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                printService = mActiveServices.get(printServiceName);
2882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
2892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            if (printService == null) {
2902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                return;
2912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
2922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            printService.onRequestCancelPrintJob(printJobInfo);
2932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } else {
2942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            // If the print job is failed we do not need cooperation
2952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            // from the print service.
2962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
2972fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
2982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
2992fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
3002fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void restartPrintJob(PrintJobId printJobId, int appId) {
3012fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
3022fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
3032fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
3042fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
3052fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
3062fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
3072fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
308860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    public List<PrintServiceInfo> getEnabledPrintServices() {
309860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        synchronized (mLock) {
310860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            List<PrintServiceInfo> enabledServices = null;
311860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            final int installedServiceCount = mInstalledServices.size();
312860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            for (int i = 0; i < installedServiceCount; i++) {
313860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                PrintServiceInfo installedService = mInstalledServices.get(i);
314860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                ComponentName componentName = new ComponentName(
315860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                        installedService.getResolveInfo().serviceInfo.packageName,
316860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                        installedService.getResolveInfo().serviceInfo.name);
317860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                if (mActiveServices.containsKey(componentName)) {
318860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                    if (enabledServices == null) {
319860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                        enabledServices = new ArrayList<PrintServiceInfo>();
320860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                    }
321860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                    enabledServices.add(installedService);
322860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov                }
323860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            }
324860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            return enabledServices;
325860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        }
326860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    }
327860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov
328d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    public List<PrintServiceInfo> getInstalledPrintServices() {
329d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        synchronized (mLock) {
330d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            return mInstalledServices;
331d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        }
332d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    }
333d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav
33444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
335a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
336a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
337a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mActiveServices.isEmpty()) {
338a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return;
339a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
34044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
34144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                // If we do not have a session, tell all service to create one.
34244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
34344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    @Override
34444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    public void onDestroyed() {
34544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        mPrinterDiscoverySession = null;
34644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    }
34744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                };
34844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                // Add the observer to the brand new session.
34944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrinterDiscoverySession.addObserverLocked(observer);
35044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } else {
35144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                // If services have created session, just add the observer.
35244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mPrinterDiscoverySession.addObserverLocked(observer);
35344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
354a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
35544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
35644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
35744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
35844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
35944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Already destroyed - nothing to do.
36044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
36144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
36244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
36344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Remove this observer.
36444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.removeObserverLocked(observer);
365269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
366269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
367269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
36844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
36944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterId> printerIds) {
370269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
371269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throwIfDestroyedLocked();
37244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No services - nothing to do.
373269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mActiveServices.isEmpty()) {
374269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
375269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
37644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No session - nothing to do.
37744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
37844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
37944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
38044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Kick of discovery.
38144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.startPrinterDiscoveryLocked(observer,
38244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    printerIds);
383269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
384269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
385269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
38644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
387269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
388269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throwIfDestroyedLocked();
38944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No services - nothing to do.
390269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mActiveServices.isEmpty()) {
391269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
392269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
39344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No session - nothing to do.
39444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
39544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
39644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
39744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Kick of discovery.
39844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.stopPrinterDiscoveryLocked(observer);
399269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
400269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
401269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
402d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void validatePrinters(List<PrinterId> printerIds) {
403269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
404269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throwIfDestroyedLocked();
40544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No services - nothing to do.
406269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mActiveServices.isEmpty()) {
407269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
408269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
40944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No session - nothing to do.
41044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
41144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
41244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
41344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Request an updated.
414d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrinterDiscoverySession.validatePrintersLocked(printerIds);
415d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
416d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
417d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
418d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void startPrinterStateTracking(PrinterId printerId) {
419d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        synchronized (mLock) {
420d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            throwIfDestroyedLocked();
421d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No services - nothing to do.
422d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mActiveServices.isEmpty()) {
423d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
424d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
425d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No session - nothing to do.
426d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
427d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
428d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
429d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Request start tracking the printer.
430d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId);
431d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
432d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
433d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
434d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void stopPrinterStateTracking(PrinterId printerId) {
435d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        synchronized (mLock) {
436d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            throwIfDestroyedLocked();
437d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No services - nothing to do.
438d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mActiveServices.isEmpty()) {
439d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
440d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
441d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No session - nothing to do.
442d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
443d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
444d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
445d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Request stop tracking the printer.
446d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId);
447269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
44844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
44944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
450704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
451704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            int appId) throws RemoteException {
452704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        synchronized (mLock) {
453704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            throwIfDestroyedLocked();
454704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (mPrintJobStateChangeListenerRecords == null) {
455704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                mPrintJobStateChangeListenerRecords =
456704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        new ArrayList<PrintJobStateChangeListenerRecord>();
457704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
458704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            mPrintJobStateChangeListenerRecords.add(
459704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    new PrintJobStateChangeListenerRecord(listener, appId) {
460704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                @Override
461704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                public void onBinderDied() {
462704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    mPrintJobStateChangeListenerRecords.remove(this);
463704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
464704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            });
465704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
466704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
467704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
468704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
469704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        synchronized (mLock) {
470704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            throwIfDestroyedLocked();
471704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (mPrintJobStateChangeListenerRecords == null) {
472704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                return;
473704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
474704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            final int recordCount = mPrintJobStateChangeListenerRecords.size();
475704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            for (int i = 0; i < recordCount; i++) {
476704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                PrintJobStateChangeListenerRecord record =
477704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                        mPrintJobStateChangeListenerRecords.get(i);
478704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                if (record.listener.asBinder().equals(listener.asBinder())) {
479704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    mPrintJobStateChangeListenerRecords.remove(i);
480704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    break;
481704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
482704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
483704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (mPrintJobStateChangeListenerRecords.isEmpty()) {
484704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                mPrintJobStateChangeListenerRecords = null;
485704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
486704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
487704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
488704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
489704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    @Override
490dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    public void onPrintJobStateChanged(PrintJobInfo printJob) {
491dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        mPrintJobForAppCache.onPrintJobStateChanged(printJob);
492704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_JOB_STATE_CHANGED,
493dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                printJob.getAppId(), 0, printJob.getId()).sendToTarget();
494704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
495704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
496c6066799ad130140159230d14451b429eb828755Svetoslav    @Override
49744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void onPrintersAdded(List<PrinterInfo> printers) {
49844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
49944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            throwIfDestroyedLocked();
50044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No services - nothing to do.
50144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mActiveServices.isEmpty()) {
50244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
50344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
50444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No session - nothing to do.
50544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
50644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
50744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
50844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.onPrintersAddedLocked(printers);
509269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
510269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
511269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
512c6066799ad130140159230d14451b429eb828755Svetoslav    @Override
51344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void onPrintersRemoved(List<PrinterId> printerIds) {
514269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        synchronized (mLock) {
515269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throwIfDestroyedLocked();
51644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No services - nothing to do.
517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            if (mActiveServices.isEmpty()) {
518269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                return;
519269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
52044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No session - nothing to do.
52144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mPrinterDiscoverySession == null) {
52244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
52344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
52444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
525269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
52644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
52744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
528c6066799ad130140159230d14451b429eb828755Svetoslav    @Override
529c6066799ad130140159230d14451b429eb828755Svetoslav    public void onServiceDied(RemotePrintService service) {
530c6066799ad130140159230d14451b429eb828755Svetoslav        synchronized (mLock) {
531c6066799ad130140159230d14451b429eb828755Svetoslav            throwIfDestroyedLocked();
532c6066799ad130140159230d14451b429eb828755Svetoslav            // No services - nothing to do.
533c6066799ad130140159230d14451b429eb828755Svetoslav            if (mActiveServices.isEmpty()) {
534c6066799ad130140159230d14451b429eb828755Svetoslav                return;
535c6066799ad130140159230d14451b429eb828755Svetoslav            }
536c6066799ad130140159230d14451b429eb828755Svetoslav            // Fail all print jobs.
537c6066799ad130140159230d14451b429eb828755Svetoslav            failActivePrintJobsForService(service.getComponentName());
538de4fa2dfe2e681c79e27d84604b9c48c68184aefSvetoslav Ganov            service.onAllPrintJobsHandled();
539c6066799ad130140159230d14451b429eb828755Svetoslav            // No session - nothing to do.
540c6066799ad130140159230d14451b429eb828755Svetoslav            if (mPrinterDiscoverySession == null) {
541c6066799ad130140159230d14451b429eb828755Svetoslav                return;
542c6066799ad130140159230d14451b429eb828755Svetoslav            }
543c6066799ad130140159230d14451b429eb828755Svetoslav            mPrinterDiscoverySession.onServiceDiedLocked(service);
544c6066799ad130140159230d14451b429eb828755Svetoslav        }
545c6066799ad130140159230d14451b429eb828755Svetoslav    }
546c6066799ad130140159230d14451b429eb828755Svetoslav
547a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void updateIfNeededLocked() {
548a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfDestroyedLocked();
549a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (readConfigurationLocked()) {
550a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            onConfigurationChangedLocked();
551a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
552a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
553a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
554a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public Set<ComponentName> getEnabledServices() {
555a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized(mLock) {
556a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
557a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mEnabledServices;
558a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
559a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
560a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
561a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void destroyLocked() {
562a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfDestroyedLocked();
563a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mSpooler.destroy();
564a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        for (RemotePrintService service : mActiveServices.values()) {
565a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            service.destroy();
566a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
567a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mActiveServices.clear();
568a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mInstalledServices.clear();
569a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mEnabledServices.clear();
57044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        if (mPrinterDiscoverySession != null) {
57144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession.destroyLocked();
57244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mPrinterDiscoverySession = null;
57344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
574a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mDestroyed = true;
575a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
576a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
577b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
578b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
579b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.println();
580b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
581b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        String tab = "  ";
582b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
583b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append(tab).append("installed services:").println();
584b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        final int installedServiceCount = mInstalledServices.size();
585b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        for (int i = 0; i < installedServiceCount; i++) {
586b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            PrintServiceInfo installedService = mInstalledServices.get(i);
587b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            String installedServicePrefix = prefix + tab + tab;
588b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(installedServicePrefix).append("service:").println();
589b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            ResolveInfo resolveInfo = installedService.getResolveInfo();
590b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            ComponentName componentName = new ComponentName(
591b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    resolveInfo.serviceInfo.packageName,
592b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    resolveInfo.serviceInfo.name);
593b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(installedServicePrefix).append(tab).append("componentName=")
594b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(componentName.flattenToString()).println();
595b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(installedServicePrefix).append(tab).append("settingsActivity=")
596b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(installedService.getSettingsActivityName()).println();
597b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(installedServicePrefix).append(tab).append("addPrintersActivity=")
598b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(installedService.getAddPrintersActivityName()).println();
599dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            pw.append(installedServicePrefix).append(tab).append("avancedOptionsActivity=")
600dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav                   .append(installedService.getAdvancedOptionsActivityName()).println();
601b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
602b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
603b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append(tab).append("enabled services:").println();
604b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        for (ComponentName enabledService : mEnabledServices) {
605b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            String enabledServicePrefix = prefix + tab + tab;
606b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(enabledServicePrefix).append("service:").println();
607b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(enabledServicePrefix).append(tab).append("componentName=")
608b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(enabledService.flattenToString());
609b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.println();
610b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
611b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
612b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append(tab).append("active services:").println();
613b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        final int activeServiceCount = mActiveServices.size();
614b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        for (int i = 0; i < activeServiceCount; i++) {
615b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            RemotePrintService activeService = mActiveServices.valueAt(i);
616b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            activeService.dump(pw, prefix + tab + tab);
617b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.println();
618b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
619b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
620dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        pw.append(prefix).append(tab).append("cached print jobs:").println();
621dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        mPrintJobForAppCache.dump(pw, prefix + tab + tab);
622dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
623b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append(tab).append("discovery mediator:").println();
624b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        if (mPrinterDiscoverySession != null) {
625b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            mPrinterDiscoverySession.dump(pw, prefix + tab + tab);
626b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
627b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
628b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.append(prefix).append(tab).append("print spooler:").println();
629b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        mSpooler.dump(fd, pw, prefix + tab + tab);
630b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        pw.println();
631b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    }
632b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
633a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean readConfigurationLocked() {
634a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        boolean somethingChanged = false;
635a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        somethingChanged |= readInstalledPrintServicesLocked();
636a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        somethingChanged |= readEnabledPrintServicesLocked();
637a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return somethingChanged;
638a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
639a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
640a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean readInstalledPrintServicesLocked() {
641a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
642a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
643a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        List<ResolveInfo> installedServices = mContext.getPackageManager()
644a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES
645a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        | PackageManager.GET_META_DATA, mUserId);
646a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
647a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int installedCount = installedServices.size();
648a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        for (int i = 0, count = installedCount; i < count; i++) {
649a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            ResolveInfo installedService = installedServices.get(i);
650a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals(
651a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    installedService.serviceInfo.permission)) {
652a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                ComponentName serviceName = new ComponentName(
653a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        installedService.serviceInfo.packageName,
654a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        installedService.serviceInfo.name);
655a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Slog.w(LOG_TAG, "Skipping print service "
656a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        + serviceName.flattenToShortString()
657a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        + " since it does not require permission "
658a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        + android.Manifest.permission.BIND_PRINT_SERVICE);
659a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                continue;
660a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
661a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
662a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
663a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
6648ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav        boolean someServiceChanged = false;
6658ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav
6668ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav        if (tempPrintServices.size() != mInstalledServices.size()) {
6678ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav            someServiceChanged = true;
6688ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav        } else {
6698ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav            for (PrintServiceInfo newService: tempPrintServices) {
6708ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                final int oldServiceIndex = mInstalledServices.indexOf(newService);
6718ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                if (oldServiceIndex < 0) {
6728ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                    someServiceChanged = true;
6738ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                    break;
6748ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                }
6758ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                // PrintServiceInfo#equals compares only the id not all members,
6768ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                // so we are also comparing the members coming from meta-data.
6778ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                PrintServiceInfo oldService = mInstalledServices.get(oldServiceIndex);
6788ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                if (!TextUtils.equals(oldService.getAddPrintersActivityName(),
6798ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                            newService.getAddPrintersActivityName())
6808ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                        || !TextUtils.equals(oldService.getAdvancedOptionsActivityName(),
6818ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                                newService.getAdvancedOptionsActivityName())
6828ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                        || !TextUtils.equals(oldService.getSettingsActivityName(),
6838ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                                newService.getSettingsActivityName())) {
6848ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                    someServiceChanged = true;
6858ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                    break;
6868ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav                }
6878ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav            }
6888ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav        }
6898ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav
6908ef0c14858de7a178aac2a5a38fe1651d3592d7fSvetoslav        if (someServiceChanged) {
691a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mInstalledServices.clear();
692a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mInstalledServices.addAll(tempPrintServices);
693a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return true;
694a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
695a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
696a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return false;
697a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
698a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
699a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean readEnabledPrintServicesLocked() {
700a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
7016bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
7026bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                tempEnabledServiceNameSet);
7036bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
7046bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            mEnabledServices.clear();
7056bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            mEnabledServices.addAll(tempEnabledServiceNameSet);
7066bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            return true;
7076bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        }
7086bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        return false;
7096bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov    }
710a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
7116bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov    private void readPrintServicesFromSettingLocked(String setting,
7126bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            Set<ComponentName> outServiceNames) {
713a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
7146bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                setting, mUserId);
715a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (!TextUtils.isEmpty(settingValue)) {
716a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
717a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            splitter.setString(settingValue);
718a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            while (splitter.hasNext()) {
719a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                String string = splitter.next();
720a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                if (TextUtils.isEmpty(string)) {
721a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    continue;
722a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
723a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                ComponentName componentName = ComponentName.unflattenFromString(string);
724a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                if (componentName != null) {
7256bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                    outServiceNames.add(componentName);
726a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
727a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
728a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
729a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
730a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
731564560e46d8a075fe508514f3dbd94f29963e6ebSvetoslav    private void enableSystemPrintServicesLocked() {
7326bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        // Load enabled and installed services.
7336bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        readEnabledPrintServicesLocked();
7346bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        readInstalledPrintServicesLocked();
735d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
7366bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        // Load the system services once enabled on first boot.
7376bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>();
7386bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        readPrintServicesFromSettingLocked(
7396bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
7406bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                enabledOnFirstBoot);
741d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
7426bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        StringBuilder builder = new StringBuilder();
743d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
7446bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        final int serviceCount = mInstalledServices.size();
7456bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        for (int i = 0; i < serviceCount; i++) {
7466bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo;
7476bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            // Enable system print services if we never did that and are not enabled.
7486bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
7496bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                ComponentName serviceName = new ComponentName(
7506bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                        serviceInfo.packageName, serviceInfo.name);
7516bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                if (!mEnabledServices.contains(serviceName)
7526bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                        && !enabledOnFirstBoot.contains(serviceName)) {
753d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (builder.length() > 0) {
754d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        builder.append(":");
755d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
756d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    builder.append(serviceName.flattenToString());
757d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                }
758d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
7596bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        }
7606bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov
7616bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        // Nothing to be enabled - done.
7626bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        if (builder.length() <= 0) {
7636bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            return;
7646bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        }
7656bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov
7666bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        String servicesToEnable = builder.toString();
767d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
7686bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        // Update the enabled services setting.
7696bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        String enabledServices = Settings.Secure.getStringForUser(
7706bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
7716bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        if (TextUtils.isEmpty(enabledServices)) {
7726bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            enabledServices = servicesToEnable;
7736bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        } else {
7746bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            enabledServices = enabledServices + ":" + servicesToEnable;
7756bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        }
7766bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        Settings.Secure.putStringForUser(mContext.getContentResolver(),
7776bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId);
7786bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov
7796bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        // Update the enabled on first boot services setting.
7806bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        String enabledOnFirstBootServices = Settings.Secure.getStringForUser(
7816bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                mContext.getContentResolver(),
7826bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId);
7836bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        if (TextUtils.isEmpty(enabledOnFirstBootServices)) {
7846bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            enabledOnFirstBootServices = servicesToEnable;
7856bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        } else {
7866bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov            enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices;
787d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
7886bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov        Settings.Secure.putStringForUser(mContext.getContentResolver(),
7896bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
7906bd20bc46c762860cac852888df5adf718f2be24Svetoslav Ganov                enabledOnFirstBootServices, mUserId);
791d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
792d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
793a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void onConfigurationChangedLocked() {
794dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav        Set<ComponentName> installedComponents = new ArraySet<ComponentName>();
795dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav
796a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int installedCount = mInstalledServices.size();
797a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        for (int i = 0; i < installedCount; i++) {
798a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo();
799a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName,
800a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    resolveInfo.serviceInfo.name);
801dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav
802dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            installedComponents.add(serviceName);
803dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav
804a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mEnabledServices.contains(serviceName)) {
805a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                if (!mActiveServices.containsKey(serviceName)) {
80644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    RemotePrintService service = new RemotePrintService(
80744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                            mContext, serviceName, mUserId, mSpooler, this);
808c6066799ad130140159230d14451b429eb828755Svetoslav                    addServiceLocked(service);
809a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
810a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } else {
811a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                RemotePrintService service = mActiveServices.remove(serviceName);
812a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                if (service != null) {
813c6066799ad130140159230d14451b429eb828755Svetoslav                    removeServiceLocked(service);
814a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
815a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
816a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
817dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav
818dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav        Iterator<Map.Entry<ComponentName, RemotePrintService>> iterator =
819dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav                mActiveServices.entrySet().iterator();
820dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav        while (iterator.hasNext()) {
821dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            Map.Entry<ComponentName, RemotePrintService> entry = iterator.next();
822dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            ComponentName serviceName = entry.getKey();
823dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            RemotePrintService service = entry.getValue();
824dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            if (!installedComponents.contains(serviceName)) {
825dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav                removeServiceLocked(service);
826dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav                iterator.remove();
827dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav            }
828dbcc95d4d889c4de2490870cfeb97cc8f6deb30eSvetoslav        }
829a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
830a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
831c6066799ad130140159230d14451b429eb828755Svetoslav    private void addServiceLocked(RemotePrintService service) {
832c6066799ad130140159230d14451b429eb828755Svetoslav        mActiveServices.put(service.getComponentName(), service);
833c6066799ad130140159230d14451b429eb828755Svetoslav        if (mPrinterDiscoverySession != null) {
834c6066799ad130140159230d14451b429eb828755Svetoslav            mPrinterDiscoverySession.onServiceAddedLocked(service);
835c6066799ad130140159230d14451b429eb828755Svetoslav        }
836c6066799ad130140159230d14451b429eb828755Svetoslav    }
837c6066799ad130140159230d14451b429eb828755Svetoslav
838c6066799ad130140159230d14451b429eb828755Svetoslav    private void removeServiceLocked(RemotePrintService service) {
839c6066799ad130140159230d14451b429eb828755Svetoslav        // Fail all print jobs.
840c6066799ad130140159230d14451b429eb828755Svetoslav        failActivePrintJobsForService(service.getComponentName());
841c6066799ad130140159230d14451b429eb828755Svetoslav        // If discovery is in progress, tear down the service.
842c6066799ad130140159230d14451b429eb828755Svetoslav        if (mPrinterDiscoverySession != null) {
843c6066799ad130140159230d14451b429eb828755Svetoslav            mPrinterDiscoverySession.onServiceRemovedLocked(service);
844c6066799ad130140159230d14451b429eb828755Svetoslav        } else {
845c6066799ad130140159230d14451b429eb828755Svetoslav            // Otherwise, just destroy it.
846c6066799ad130140159230d14451b429eb828755Svetoslav            service.destroy();
847c6066799ad130140159230d14451b429eb828755Svetoslav        }
848c6066799ad130140159230d14451b429eb828755Svetoslav    }
849c6066799ad130140159230d14451b429eb828755Svetoslav
850c6066799ad130140159230d14451b429eb828755Svetoslav    private void failActivePrintJobsForService(final ComponentName serviceName) {
851c6066799ad130140159230d14451b429eb828755Svetoslav        // Makes sure all active print jobs are failed since the service
852c6066799ad130140159230d14451b429eb828755Svetoslav        // just died. Do this off the main thread since we do to allow
853c6066799ad130140159230d14451b429eb828755Svetoslav        // calls into the spooler on the main thread.
854c6066799ad130140159230d14451b429eb828755Svetoslav        if (Looper.getMainLooper().isCurrentThread()) {
8552fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            BackgroundThread.getHandler().post(new Runnable() {
856c6066799ad130140159230d14451b429eb828755Svetoslav                @Override
8572fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                public void run() {
8589b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                    failScheduledPrintJobsForServiceInternal(serviceName);
859c6066799ad130140159230d14451b429eb828755Svetoslav                }
8602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            });
861c6066799ad130140159230d14451b429eb828755Svetoslav        } else {
8629b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov            failScheduledPrintJobsForServiceInternal(serviceName);
863c6066799ad130140159230d14451b429eb828755Svetoslav        }
864c6066799ad130140159230d14451b429eb828755Svetoslav    }
865c6066799ad130140159230d14451b429eb828755Svetoslav
8669b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov    private void failScheduledPrintJobsForServiceInternal(ComponentName serviceName) {
867c6066799ad130140159230d14451b429eb828755Svetoslav        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName,
8689b6d3a153f44010a75907c6a9742c89a57d4e5eeSvetoslav Ganov                PrintJobInfo.STATE_ANY_SCHEDULED, PrintManager.APP_ID_ANY);
869c6066799ad130140159230d14451b429eb828755Svetoslav        if (printJobs == null) {
870c6066799ad130140159230d14451b429eb828755Svetoslav            return;
871c6066799ad130140159230d14451b429eb828755Svetoslav        }
872c6066799ad130140159230d14451b429eb828755Svetoslav        final long identity = Binder.clearCallingIdentity();
873c6066799ad130140159230d14451b429eb828755Svetoslav        try {
874c6066799ad130140159230d14451b429eb828755Svetoslav            final int printJobCount = printJobs.size();
875c6066799ad130140159230d14451b429eb828755Svetoslav            for (int i = 0; i < printJobCount; i++) {
876c6066799ad130140159230d14451b429eb828755Svetoslav                PrintJobInfo printJob = printJobs.get(i);
877c6066799ad130140159230d14451b429eb828755Svetoslav                mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
878db85ad56adb74f0310b604228dac8bbc03ac2769Svetoslav Ganov                        mContext.getString(R.string.reason_service_unavailable));
879c6066799ad130140159230d14451b429eb828755Svetoslav            }
880c6066799ad130140159230d14451b429eb828755Svetoslav        } finally {
881c6066799ad130140159230d14451b429eb828755Svetoslav            Binder.restoreCallingIdentity(identity);
882c6066799ad130140159230d14451b429eb828755Svetoslav        }
883c6066799ad130140159230d14451b429eb828755Svetoslav    }
884c6066799ad130140159230d14451b429eb828755Svetoslav
885a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void throwIfDestroyedLocked() {
886a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (mDestroyed) {
887a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new IllegalStateException("Cannot interact with a destroyed instance.");
888a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
889a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
890a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
891704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private void handleDispatchPrintJobStateChanged(PrintJobId printJobId, int appId) {
892704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final List<PrintJobStateChangeListenerRecord> records;
893704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        synchronized (mLock) {
894704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (mPrintJobStateChangeListenerRecords == null) {
895704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                return;
896704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
897704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            records = new ArrayList<PrintJobStateChangeListenerRecord>(
898704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    mPrintJobStateChangeListenerRecords);
899704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
900704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final int recordCount = records.size();
901704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        for (int i = 0; i < recordCount; i++) {
902704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            PrintJobStateChangeListenerRecord record = records.get(i);
903704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (record.appId == PrintManager.APP_ID_ANY
904704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    || record.appId == appId)
905704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            try {
906704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                record.listener.onPrintJobStateChanged(printJobId);
907704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            } catch (RemoteException re) {
908704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                Log.e(LOG_TAG, "Error notifying for print job state change", re);
909704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
910704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
911704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
912704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
913704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private final class UserStateHandler extends Handler {
914704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
915704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
916704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public UserStateHandler(Looper looper) {
917704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            super(looper, null, false);
918704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
919704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
920704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        @Override
921704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public void handleMessage(Message message) {
922704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) {
923704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                PrintJobId printJobId = (PrintJobId) message.obj;
924704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final int appId = message.arg1;
925704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                handleDispatchPrintJobStateChanged(printJobId, appId);
926704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
927704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
928704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
929704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
930704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
931704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final IPrintJobStateChangeListener listener;
932704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final int appId;
933704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
934704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
935704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                int appId) throws RemoteException {
936704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            this.listener = listener;
937704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            this.appId = appId;
938704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            listener.asBinder().linkToDeath(this, 0);
939704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
940704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
941704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        @Override
942704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public void binderDied() {
943704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            listener.asBinder().unlinkToDeath(this, 0);
944704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            onBinderDied();
945704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
946704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
947704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        public abstract void onBinderDied();
948704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
949704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
95044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private class PrinterDiscoverySessionMediator {
95144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
95244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                new ArrayMap<PrinterId, PrinterInfo>();
95344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
95444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final RemoteCallbackList<IPrinterDiscoveryObserver> mDiscoveryObservers =
95544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                new RemoteCallbackList<IPrinterDiscoveryObserver>() {
95644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            @Override
95744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public void onCallbackDied(IPrinterDiscoveryObserver observer) {
95844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                synchronized (mLock) {
95944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    stopPrinterDiscoveryLocked(observer);
96044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    removeObserverLocked(observer);
96144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                }
96244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
96344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        };
96444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
96544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>();
96644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
967d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
968d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
96944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final Handler mHandler;
97044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
97144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private boolean mIsDestroyed;
97244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
97344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public PrinterDiscoverySessionMediator(Context context) {
97444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler = new SessionHandler(context.getMainLooper());
97544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Kick off the session creation.
97644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
97744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    mActiveServices.values());
97844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
97944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
98044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .sendToTarget();
98144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
98244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
98344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void addObserverLocked(IPrinterDiscoveryObserver observer) {
98444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Add the observer.
98544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mDiscoveryObservers.register(observer);
98644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
98744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Bring the added observer up to speed with the printers.
98844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (!mPrinters.isEmpty()) {
98944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values());
99044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                SomeArgs args = SomeArgs.obtain();
99144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                args.arg1 = observer;
99244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                args.arg2 = printers;
99344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
99444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        args).sendToTarget();
99544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
99644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
99744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
99844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
99944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Remove the observer.
100044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mDiscoveryObservers.unregister(observer);
100144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // No one else observing - then kill it.
100244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mDiscoveryObservers.getRegisteredCallbackCount() == 0) {
100344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                destroyLocked();
100444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
100544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
100644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
100744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
100844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                List<PrinterId> priorityList) {
100944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
101044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
101144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
101244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
101344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1014c6066799ad130140159230d14451b429eb828755Svetoslav            final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty();
1015c6066799ad130140159230d14451b429eb828755Svetoslav
1016c6066799ad130140159230d14451b429eb828755Svetoslav            // Remember we got a start request to match with an end.
1017c6066799ad130140159230d14451b429eb828755Svetoslav            mStartedPrinterDiscoveryTokens.add(observer.asBinder());
1018c6066799ad130140159230d14451b429eb828755Svetoslav
101944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // If printer discovery is ongoing and the start request has a list
1020d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // of printer to be checked, then we just request validating them.
1021c6066799ad130140159230d14451b429eb828755Svetoslav            if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) {
1022d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                validatePrinters(priorityList);
102344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
102444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
102544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
102644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // The service are already performing discovery - nothing to do.
102744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mStartedPrinterDiscoveryTokens.size() > 1) {
102844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
102944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
10309186d0cb2bd325d9b52da15dbd513937c1e42caaSvetoslav Ganov
103144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
103244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    mActiveServices.values());
103344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            SomeArgs args = SomeArgs.obtain();
103444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            args.arg1 = services;
103544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            args.arg2 = priorityList;
103644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
103744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
103844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .sendToTarget();
103944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
104044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
104144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
104244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
104344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
104444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
104544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
104644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // This one did not make an active discovery request - nothing to do.
104744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (!mStartedPrinterDiscoveryTokens.remove(observer.asBinder())) {
104844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
104944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
105044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // There are other interested observers - do not stop discovery.
105144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
105244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
105344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
105444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
105544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    mActiveServices.values());
105644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
105744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
105844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .sendToTarget();
105944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
106044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1061d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public void validatePrintersLocked(List<PrinterId> printerIds) {
106244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
1063d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                Log.w(LOG_TAG, "Not validating pritners - session destroyed");
106444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
106544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
1066d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1067d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds);
1068d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            while (!remainingList.isEmpty()) {
1069d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                Iterator<PrinterId> iterator = remainingList.iterator();
1070d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                // Gather the printers per service and request a validation.
1071d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                List<PrinterId> updateList = new ArrayList<PrinterId>();
1072d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                ComponentName serviceName = null;
1073d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                while (iterator.hasNext()) {
1074d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    PrinterId printerId = iterator.next();
1075d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (updateList.isEmpty()) {
1076d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        updateList.add(printerId);
1077d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        serviceName = printerId.getServiceName();
1078d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        iterator.remove();
1079d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    } else if (printerId.getServiceName().equals(serviceName)) {
1080d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        updateList.add(printerId);
1081d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        iterator.remove();
1082d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
1083d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                }
1084d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                // Schedule a notification of the service.
1085d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                RemotePrintService service = mActiveServices.get(serviceName);
1086d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                if (service != null) {
1087d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    SomeArgs args = SomeArgs.obtain();
1088d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    args.arg1 = service;
1089d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    args.arg2 = updateList;
1090d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    mHandler.obtainMessage(SessionHandler
1091d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                            .MSG_VALIDATE_PRINTERS, args)
1092d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                            .sendToTarget();
1093d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                }
1094d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1095d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
1096d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1097d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public final void startPrinterStateTrackingLocked(PrinterId printerId) {
1098d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mIsDestroyed) {
1099d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
1100d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1101d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1102d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // If printer discovery is not started - nothing to do.
1103d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mStartedPrinterDiscoveryTokens.isEmpty()) {
1104d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1105d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1106d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId);
1107d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Keep track of the number of requests to track this one.
1108d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mStateTrackedPrinters.add(printerId);
1109d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // If we were tracking this printer - nothing to do.
1110d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (containedPrinterId) {
1111d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1112d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1113d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No service - nothing to do.
111444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            RemotePrintService service = mActiveServices.get(printerId.getServiceName());
1115d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (service == null) {
1116d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
111744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
1118d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Ask the service to start tracking.
1119d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            SomeArgs args = SomeArgs.obtain();
1120d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            args.arg1 = service;
1121d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            args.arg2 = printerId;
1122d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
1123d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    .MSG_START_PRINTER_STATE_TRACKING, args)
1124d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    .sendToTarget();
1125d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
1126d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1127d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public final void stopPrinterStateTrackingLocked(PrinterId printerId) {
1128d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mIsDestroyed) {
1129d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed");
1130d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1131d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1132d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // If printer discovery is not started - nothing to do.
1133d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (mStartedPrinterDiscoveryTokens.isEmpty()) {
1134d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1135d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1136d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // If we did not track this printer - nothing to do.
1137d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (!mStateTrackedPrinters.remove(printerId)) {
1138d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1139d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1140d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // No service - nothing to do.
1141d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            RemotePrintService service = mActiveServices.get(printerId.getServiceName());
1142d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            if (service == null) {
1143d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                return;
1144d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
1145d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Ask the service to start tracking.
1146d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            SomeArgs args = SomeArgs.obtain();
1147d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            args.arg1 = service;
1148d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            args.arg2 = printerId;
1149d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
1150d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    .MSG_STOP_PRINTER_STATE_TRACKING, args)
1151d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    .sendToTarget();
115244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
115344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
115444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onDestroyed() {
115544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            /* do nothing */
115644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
115744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
115844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void destroyLocked() {
115944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
116044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not destroying - session destroyed");
116144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
116244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
1163564560e46d8a075fe508514f3dbd94f29963e6ebSvetoslav            mIsDestroyed = true;
1164d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            // Make sure printer tracking is stopped.
1165d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            final int printerCount = mStateTrackedPrinters.size();
1166d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            for (int i = 0; i < printerCount; i++) {
1167d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                PrinterId printerId = mStateTrackedPrinters.get(i);
1168d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                stopPrinterStateTracking(printerId);
1169d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
117044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Make sure discovery is stopped.
117144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int observerCount = mStartedPrinterDiscoveryTokens.size();
117244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < observerCount; i++) {
117344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                IBinder token = mStartedPrinterDiscoveryTokens.get(i);
117444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token));
117544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
117644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Tell the services we are done.
117744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<RemotePrintService> services = new ArrayList<RemotePrintService>(
117844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    mActiveServices.values());
117944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler.obtainMessage(SessionHandler
118044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
118144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    .sendToTarget();
118244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
118344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
118444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onPrintersAddedLocked(List<PrinterInfo> printers) {
118544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (DEBUG) {
118644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.i(LOG_TAG, "onPrintersAddedLocked()");
118744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
118844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
118944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not adding printers - session destroyed");
119044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
119144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
119244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterInfo> addedPrinters = null;
119344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int addedPrinterCount = printers.size();
119444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < addedPrinterCount; i++) {
119544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                PrinterInfo printer = printers.get(i);
1196773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                PrinterInfo oldPrinter = mPrinters.put(printer.getId(), printer);
1197773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav                if (oldPrinter == null || !oldPrinter.equals(printer)) {
119844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    if (addedPrinters == null) {
119944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        addedPrinters = new ArrayList<PrinterInfo>();
120044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    }
120144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    addedPrinters.add(printer);
120244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                }
120344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
120444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (addedPrinters != null) {
120544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
120644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        addedPrinters).sendToTarget();
120744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
120844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
120944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
121044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onPrintersRemovedLocked(List<PrinterId> printerIds) {
121144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (DEBUG) {
121244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.i(LOG_TAG, "onPrintersRemovedLocked()");
121344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
121444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
121544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not removing printers - session destroyed");
121644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
121744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
121844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterId> removedPrinterIds = null;
121944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int removedPrinterCount = printerIds.size();
122044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < removedPrinterCount; i++) {
122144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                PrinterId removedPrinterId = printerIds.get(i);
122244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                if (mPrinters.remove(removedPrinterId) != null) {
122344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    if (removedPrinterIds == null) {
122444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        removedPrinterIds = new ArrayList<PrinterId>();
122544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    }
122644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    removedPrinterIds.add(removedPrinterId);
122744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                }
122844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
122944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (removedPrinterIds != null) {
123044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
123144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        removedPrinterIds).sendToTarget();
123244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
123344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
123444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1235c6066799ad130140159230d14451b429eb828755Svetoslav        public void onServiceRemovedLocked(RemotePrintService service) {
123644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
123744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not updating removed service - session destroyed");
123844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
123944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
1240c6066799ad130140159230d14451b429eb828755Svetoslav            // Remove the reported and tracked printers for that service.
1241c6066799ad130140159230d14451b429eb828755Svetoslav            ComponentName serviceName = service.getComponentName();
1242c6066799ad130140159230d14451b429eb828755Svetoslav            removePrintersForServiceLocked(serviceName);
1243c6066799ad130140159230d14451b429eb828755Svetoslav            service.destroy();
1244c6066799ad130140159230d14451b429eb828755Svetoslav        }
1245c6066799ad130140159230d14451b429eb828755Svetoslav
1246c6066799ad130140159230d14451b429eb828755Svetoslav        public void onServiceDiedLocked(RemotePrintService service) {
1247c6066799ad130140159230d14451b429eb828755Svetoslav            // Remove the reported by that service.
1248c6066799ad130140159230d14451b429eb828755Svetoslav            removePrintersForServiceLocked(service.getComponentName());
124944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
125044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
125144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        public void onServiceAddedLocked(RemotePrintService service) {
125244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            if (mIsDestroyed) {
125344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.w(LOG_TAG, "Not updating added service - session destroyed");
125444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                return;
125544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
125644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // Tell the service to create a session.
125744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mHandler.obtainMessage(
125844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
125944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    service).sendToTarget();
1260b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            // Start printer discovery if necessary.
1261b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
126244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mHandler.obtainMessage(
126344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        SessionHandler.MSG_START_PRINTER_DISCOVERY,
126444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        service).sendToTarget();
126544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
1266b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            // Start tracking printers if necessary
1267b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            final int trackedPrinterCount = mStateTrackedPrinters.size();
1268b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            for (int i = 0; i < trackedPrinterCount; i++) {
1269b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                PrinterId printerId = mStateTrackedPrinters.get(i);
1270b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                if (printerId.getServiceName().equals(service.getComponentName())) {
1271b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    SomeArgs args = SomeArgs.obtain();
1272b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    args.arg1 = service;
1273b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    args.arg2 = printerId;
1274b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    mHandler.obtainMessage(SessionHandler
1275b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                            .MSG_START_PRINTER_STATE_TRACKING, args)
1276b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                            .sendToTarget();
1277b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                }
1278b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav            }
127944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
128044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1281b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        public void dump(PrintWriter pw, String prefix) {
1282b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("destroyed=")
1283b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(String.valueOf(mDestroyed)).println();
1284b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1285b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("printDiscoveryInProgress=")
1286b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(String.valueOf(!mStartedPrinterDiscoveryTokens.isEmpty())).println();
1287b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1288b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            String tab = "  ";
1289b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1290b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append(tab).append("printer discovery observers:").println();
1291b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            final int observerCount = mDiscoveryObservers.beginBroadcast();
1292b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            for (int i = 0; i < observerCount; i++) {
1293b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
1294b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                pw.append(prefix).append(prefix).append(observer.toString());
1295b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                pw.println();
1296b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
1297b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            mDiscoveryObservers.finishBroadcast();
1298b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1299b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append(tab).append("start discovery requests:").println();
1300b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            final int tokenCount = this.mStartedPrinterDiscoveryTokens.size();
1301b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            for (int i = 0; i < tokenCount; i++) {
1302b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                IBinder token = mStartedPrinterDiscoveryTokens.get(i);
1303b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                pw.append(prefix).append(tab).append(tab).append(token.toString()).println();
1304b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
1305b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1306b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append(tab).append("tracked printer requests:").println();
1307b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            final int trackedPrinters = mStateTrackedPrinters.size();
1308b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            for (int i = 0; i < trackedPrinters; i++) {
1309b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                PrinterId printer = mStateTrackedPrinters.get(i);
1310b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                pw.append(prefix).append(tab).append(tab).append(printer.toString()).println();
1311b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
1312b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1313b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append(tab).append("printers:").println();
1314b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            final int pritnerCount = mPrinters.size();
1315b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            for (int i = 0; i < pritnerCount; i++) {
1316b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                PrinterInfo printer = mPrinters.valueAt(i);
1317b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                pw.append(prefix).append(tab).append(tab).append(
1318b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                        printer.toString()).println();
1319b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
1320b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
1321b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1322c6066799ad130140159230d14451b429eb828755Svetoslav        private void removePrintersForServiceLocked(ComponentName serviceName) {
1323c6066799ad130140159230d14451b429eb828755Svetoslav            // No printers - nothing to do.
1324c6066799ad130140159230d14451b429eb828755Svetoslav            if (mPrinters.isEmpty()) {
1325c6066799ad130140159230d14451b429eb828755Svetoslav                return;
1326c6066799ad130140159230d14451b429eb828755Svetoslav            }
1327c6066799ad130140159230d14451b429eb828755Svetoslav            // Remove the printers for that service.
1328c6066799ad130140159230d14451b429eb828755Svetoslav            List<PrinterId> removedPrinterIds = null;
1329c6066799ad130140159230d14451b429eb828755Svetoslav            final int printerCount = mPrinters.size();
1330c6066799ad130140159230d14451b429eb828755Svetoslav            for (int i = 0; i < printerCount; i++) {
1331c6066799ad130140159230d14451b429eb828755Svetoslav                PrinterId printerId = mPrinters.keyAt(i);
1332c6066799ad130140159230d14451b429eb828755Svetoslav                if (printerId.getServiceName().equals(serviceName)) {
1333c6066799ad130140159230d14451b429eb828755Svetoslav                    if (removedPrinterIds == null) {
1334c6066799ad130140159230d14451b429eb828755Svetoslav                        removedPrinterIds = new ArrayList<PrinterId>();
1335c6066799ad130140159230d14451b429eb828755Svetoslav                    }
1336c6066799ad130140159230d14451b429eb828755Svetoslav                    removedPrinterIds.add(printerId);
1337c6066799ad130140159230d14451b429eb828755Svetoslav                }
1338c6066799ad130140159230d14451b429eb828755Svetoslav            }
1339c6066799ad130140159230d14451b429eb828755Svetoslav            if (removedPrinterIds != null) {
1340de4fa2dfe2e681c79e27d84604b9c48c68184aefSvetoslav Ganov                final int removedPrinterCount = removedPrinterIds.size();
1341de4fa2dfe2e681c79e27d84604b9c48c68184aefSvetoslav Ganov                for (int i = 0; i < removedPrinterCount; i++) {
1342de4fa2dfe2e681c79e27d84604b9c48c68184aefSvetoslav Ganov                    mPrinters.remove(removedPrinterIds.get(i));
1343de4fa2dfe2e681c79e27d84604b9c48c68184aefSvetoslav Ganov                }
1344c6066799ad130140159230d14451b429eb828755Svetoslav                mHandler.obtainMessage(
1345c6066799ad130140159230d14451b429eb828755Svetoslav                        SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
1346c6066799ad130140159230d14451b429eb828755Svetoslav                        removedPrinterIds).sendToTarget();
1347c6066799ad130140159230d14451b429eb828755Svetoslav            }
1348c6066799ad130140159230d14451b429eb828755Svetoslav        }
1349c6066799ad130140159230d14451b429eb828755Svetoslav
135044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
135144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int observerCount = mDiscoveryObservers.beginBroadcast();
135244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < observerCount; i++) {
135344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
13549186d0cb2bd325d9b52da15dbd513937c1e42caaSvetoslav Ganov                handlePrintersAdded(observer, addedPrinters);
135544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
135644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mDiscoveryObservers.finishBroadcast();
135744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
135844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
135944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchPrintersRemoved(List<PrinterId> removedPrinterIds) {
136044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int observerCount = mDiscoveryObservers.beginBroadcast();
136144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < observerCount; i++) {
136244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
13639186d0cb2bd325d9b52da15dbd513937c1e42caaSvetoslav Ganov                handlePrintersRemoved(observer, removedPrinterIds);
136444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
136544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mDiscoveryObservers.finishBroadcast();
136644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
136744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
136844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchCreatePrinterDiscoverySession(
136944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                List<RemotePrintService> services) {
137044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int serviceCount = services.size();
137144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < serviceCount; i++) {
137244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                RemotePrintService service = services.get(i);
137344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                service.createPrinterDiscoverySession();
137444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
137544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
137644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
137744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchDestroyPrinterDiscoverySession(
137844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                List<RemotePrintService> services) {
137944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int serviceCount = services.size();
138044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < serviceCount; i++) {
138144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                RemotePrintService service = services.get(i);
138244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                service.destroyPrinterDiscoverySession();
138344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
138444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            onDestroyed();
138544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
138644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
138744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchStartPrinterDiscovery(
138844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                List<RemotePrintService> services, List<PrinterId> printerIds) {
138944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int serviceCount = services.size();
139044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < serviceCount; i++) {
139144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                RemotePrintService service = services.get(i);
139244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                service.startPrinterDiscovery(printerIds);
139344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
139444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
139544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
139644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handleDispatchStopPrinterDiscovery(List<RemotePrintService> services) {
139744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            final int serviceCount = services.size();
139844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            for (int i = 0; i < serviceCount; i++) {
139944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                RemotePrintService service = services.get(i);
140044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                service.stopPrinterDiscovery();
140144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
140244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
140344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1404d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private void handleValidatePrinters(RemotePrintService service,
1405d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                List<PrinterId> printerIds) {
1406d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            service.validatePrinters(printerIds);
1407d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
1408d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1409d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private void handleStartPrinterStateTracking(RemotePrintService service,
1410d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                PrinterId printerId) {
1411d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            service.startPrinterStateTracking(printerId);
1412d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
1413d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1414d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private void handleStopPrinterStateTracking(RemotePrintService service,
141544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                PrinterId printerId) {
1416d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            service.stopPrinterStateTracking(printerId);
141744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
141844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
141944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
142044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterInfo> printers) {
142144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
14222fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers));
142344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
142444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Log.e(LOG_TAG, "Error sending added printers", re);
142544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
142644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
142744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
142844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
142944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterId> printerIds) {
143044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            try {
14312fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds));
143244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            } catch (RemoteException re) {
14332fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                Log.e(LOG_TAG, "Error sending removed printers", re);
143444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
143544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
143644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
143744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        private final class SessionHandler extends Handler {
143844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public static final int MSG_PRINTERS_ADDED = 1;
143944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public static final int MSG_PRINTERS_REMOVED = 2;
144044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public static final int MSG_DISPATCH_PRINTERS_ADDED = 3;
144144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
1442773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav
1443773f54de3de9bce7b6f915aa47ed686b161d77aaSvetoslav            public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
1444c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
1445c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_START_PRINTER_DISCOVERY = 7;
1446c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
1447c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
1448c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
1449c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
1450c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
1451c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_VALIDATE_PRINTERS = 13;
1452c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
1453c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
1454c6066799ad130140159230d14451b429eb828755Svetoslav            public static final int MSG_DESTROY_SERVICE = 16;
145544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
145644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            SessionHandler(Looper looper) {
145744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                super(looper, null, false);
145844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
145944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
146044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            @Override
146144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            @SuppressWarnings("unchecked")
146244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            public void handleMessage(Message message) {
146344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                switch (message.what) {
146444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_PRINTERS_ADDED: {
146544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
146644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
146744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2;
146844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        args.recycle();
146944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handlePrintersAdded(observer, addedPrinters);
147044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
147144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
147244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_PRINTERS_REMOVED: {
147344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
147444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
147544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2;
147644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        args.recycle();
147744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handlePrintersRemoved(observer, removedPrinterIds);
147844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    }
147944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
148044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_PRINTERS_ADDED: {
148144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj;
148244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchPrintersAdded(addedPrinters);
148344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
148444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
148544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_PRINTERS_REMOVED: {
148644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj;
148744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchPrintersRemoved(removedPrinterIds);
148844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
148944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
149044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
149144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        RemotePrintService service = (RemotePrintService) message.obj;
149244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        service.createPrinterDiscoverySession();
149344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
149444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1495c6066799ad130140159230d14451b429eb828755Svetoslav                    case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
1496c6066799ad130140159230d14451b429eb828755Svetoslav                        RemotePrintService service = (RemotePrintService) message.obj;
1497c6066799ad130140159230d14451b429eb828755Svetoslav                        service.destroyPrinterDiscoverySession();
1498c6066799ad130140159230d14451b429eb828755Svetoslav                    } break;
1499c6066799ad130140159230d14451b429eb828755Svetoslav
150044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_START_PRINTER_DISCOVERY: {
150144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        RemotePrintService service = (RemotePrintService) message.obj;
150244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        service.startPrinterDiscovery(null);
150344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
150444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1505c6066799ad130140159230d14451b429eb828755Svetoslav                    case MSG_STOP_PRINTER_DISCOVERY: {
1506c6066799ad130140159230d14451b429eb828755Svetoslav                        RemotePrintService service = (RemotePrintService) message.obj;
1507c6066799ad130140159230d14451b429eb828755Svetoslav                        service.stopPrinterDiscovery();
1508c6066799ad130140159230d14451b429eb828755Svetoslav                    } break;
1509c6066799ad130140159230d14451b429eb828755Svetoslav
151044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
151144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
151244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchCreatePrinterDiscoverySession(services);
151344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
151444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
151544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: {
151644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
151744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchDestroyPrinterDiscoverySession(services);
151844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
151944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
152044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_START_PRINTER_DISCOVERY: {
152144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
152244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<RemotePrintService> services = (List<RemotePrintService>) args.arg1;
152344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
152444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        args.recycle();
152544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchStartPrinterDiscovery(services, printerIds);
152644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
152744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
152844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: {
152944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
153044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        handleDispatchStopPrinterDiscovery(services);
153144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
153244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
1533d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    case MSG_VALIDATE_PRINTERS: {
1534d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
1535d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        RemotePrintService service = (RemotePrintService) args.arg1;
1536d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
1537d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        args.recycle();
1538d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        handleValidatePrinters(service, printerIds);
1539d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    } break;
1540d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1541d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    case MSG_START_PRINTER_STATE_TRACKING: {
154244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
154344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        RemotePrintService service = (RemotePrintService) args.arg1;
154444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        PrinterId printerId = (PrinterId) args.arg2;
154544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                        args.recycle();
1546d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        handleStartPrinterStateTracking(service, printerId);
154744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    } break;
1548d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
1549d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    case MSG_STOP_PRINTER_STATE_TRACKING: {
1550d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
1551d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        RemotePrintService service = (RemotePrintService) args.arg1;
1552d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        PrinterId printerId = (PrinterId) args.arg2;
1553d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        args.recycle();
1554d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        handleStopPrinterStateTracking(service, printerId);
1555c6066799ad130140159230d14451b429eb828755Svetoslav                    } break;
1556c6066799ad130140159230d14451b429eb828755Svetoslav
1557c6066799ad130140159230d14451b429eb828755Svetoslav                    case MSG_DESTROY_SERVICE: {
1558c6066799ad130140159230d14451b429eb828755Svetoslav                        RemotePrintService service = (RemotePrintService) message.obj;
1559c6066799ad130140159230d14451b429eb828755Svetoslav                        service.destroy();
1560c6066799ad130140159230d14451b429eb828755Svetoslav                    } break;
156144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                }
156244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            }
156344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
156444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
15652fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
1566dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private final class PrintJobForAppCache {
1567dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        private final SparseArray<List<PrintJobInfo>> mPrintJobsForRunningApp =
1568dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                new SparseArray<List<PrintJobInfo>>();
15692fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
1570dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public boolean onPrintJobCreated(final IBinder creator, final int appId,
1571dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                PrintJobInfo printJob) {
15722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            try {
15732fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                creator.linkToDeath(new DeathRecipient() {
15742fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    @Override
15752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    public void binderDied() {
15762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        creator.unlinkToDeath(this, 0);
15772fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        synchronized (mLock) {
1578dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            mPrintJobsForRunningApp.remove(appId);
15792fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        }
15802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    }
15812fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                }, 0);
15822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            } catch (RemoteException re) {
15832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                /* The process is already dead - we just failed. */
15842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                return false;
15852fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
15862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            synchronized (mLock) {
1587dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
1588dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (printJobsForApp == null) {
1589dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    printJobsForApp = new ArrayList<PrintJobInfo>();
1590dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    mPrintJobsForRunningApp.put(appId, printJobsForApp);
15912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                }
1592dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                printJobsForApp.add(printJob);
15932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
15942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return true;
15952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
1596dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
1597dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void onPrintJobStateChanged(PrintJobInfo printJob) {
1598dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            synchronized (mLock) {
1599dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(
1600dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJob.getAppId());
1601dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (printJobsForApp == null) {
1602dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    return;
1603dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1604dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int printJobCount = printJobsForApp.size();
1605dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < printJobCount; i++) {
1606dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    PrintJobInfo oldPrintJob = printJobsForApp.get(i);
1607dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (oldPrintJob.getId().equals(printJob.getId())) {
1608dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJobsForApp.set(i, printJob);
1609dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
1610dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1611dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
1612dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
1613dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
1614dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public PrintJobInfo getPrintJob(PrintJobId printJobId, int appId) {
1615dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            synchronized (mLock) {
1616dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
1617dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (printJobsForApp == null) {
1618dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    return null;
1619dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1620dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int printJobCount = printJobsForApp.size();
1621dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < printJobCount; i++) {
1622dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    PrintJobInfo printJob = printJobsForApp.get(i);
1623dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (printJob.getId().equals(printJobId)) {
1624dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        return printJob;
1625dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
1626dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1627dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
1628dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            return null;
1629dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
1630dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
1631dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public List<PrintJobInfo> getPrintJobs(int appId) {
1632dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            synchronized (mLock) {
1633dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                List<PrintJobInfo> printJobs = null;
1634dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (appId == PrintManager.APP_ID_ANY) {
1635dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    final int bucketCount = mPrintJobsForRunningApp.size();
1636dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    for (int i = 0; i < bucketCount; i++) {
1637dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
1638dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        if (printJobs == null) {
1639dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            printJobs = new ArrayList<PrintJobInfo>();
1640dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        }
1641dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJobs.addAll(bucket);
1642dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
1643dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                } else {
1644dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    List<PrintJobInfo> bucket = mPrintJobsForRunningApp.get(appId);
1645dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    if (bucket != null) {
1646dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        if (printJobs == null) {
1647dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                            printJobs = new ArrayList<PrintJobInfo>();
1648dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        }
1649dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        printJobs.addAll(bucket);
1650dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
1651dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1652dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                if (printJobs != null) {
1653dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    return printJobs;
1654dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1655dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                return Collections.emptyList();
1656dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
1657dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
1658dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
1659dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void dump(PrintWriter pw, String prefix) {
1660dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            synchronized (mLock) {
1661dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                String tab = "  ";
1662dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                final int bucketCount = mPrintJobsForRunningApp.size();
1663dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                for (int i = 0; i < bucketCount; i++) {
1664dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    final int appId = mPrintJobsForRunningApp.keyAt(i);
1665dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    pw.append(prefix).append("appId=" + appId).append(':').println();
1666dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
1667dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    final int printJobCount = bucket.size();
1668dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    for (int j = 0; j < printJobCount; j++) {
1669dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        PrintJobInfo printJob = bucket.get(j);
1670dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                        pw.append(prefix).append(tab).append(printJob.toString()).println();
1671dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    }
1672dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                }
1673dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            }
1674dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        }
16752fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
16762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav}
1677