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
19a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.ComponentName;
20a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.Context;
21a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.Intent;
22a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.content.ServiceConnection;
23a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.Binder;
24f983d084e7b8a6de722d9cede1c0cf73831c8e92Svet Ganovimport android.os.Build;
25a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.IBinder;
26a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.ParcelFileDescriptor;
27a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.RemoteException;
28a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.SystemClock;
29a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.UserHandle;
30a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpooler;
31a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerCallbacks;
32a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerClient;
332fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
34a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.PrintJobInfo;
35a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.Slog;
36a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.TimedRemoteCaller;
37a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
38b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.FileDescriptor;
39b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.PrintWriter;
40a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.lang.ref.WeakReference;
41a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.List;
42a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.concurrent.TimeoutException;
43a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport libcore.io.IoUtils;
452fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
46a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov/**
47a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * This represents the remote print spooler as a local object to the
48a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav * PrintManagerService. It is responsible to connecting to the remote
49a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * spooler if needed, to make the timed remote calls, to handle
50a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * remote exceptions, and to bind/unbind to the remote instance as
51a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * needed.
52a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov */
53a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovfinal class RemotePrintSpooler {
54a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
55a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final String LOG_TAG = "RemotePrintSpooler";
56a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
57c6066799ad130140159230d14451b429eb828755Svetoslav    private static final boolean DEBUG = false;
58a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
59f983d084e7b8a6de722d9cede1c0cf73831c8e92Svet Ganov    private static final long BIND_SPOOLER_SERVICE_TIMEOUT =
60f983d084e7b8a6de722d9cede1c0cf73831c8e92Svet Ganov            ("eng".equals(Build.TYPE)) ? 120000 : 10000;
61a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
62a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Object mLock = new Object();
63a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
64a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
65a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
66a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
67a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
68a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
69a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
70a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
71a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
72a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final ServiceConnection mServiceConnection = new MyServiceConnection();
73a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
74a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Context mContext;
75a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
76a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final UserHandle mUserHandle;
77a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
78a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final PrintSpoolerClient mClient;
79a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
80a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Intent mIntent;
81a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final PrintSpoolerCallbacks mCallbacks;
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private IPrintSpooler mRemoteInstance;
85a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
86a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean mDestroyed;
87a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
8885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov    private boolean mCanUnbind;
8985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public static interface PrintSpoolerCallbacks {
91a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onPrintJobQueued(PrintJobInfo printJob);
92a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsForServiceHandled(ComponentName printService);
93dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void onPrintJobStateChanged(PrintJobInfo printJob);
94a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
95a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
96a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public RemotePrintSpooler(Context context, int userId,
97a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            PrintSpoolerCallbacks callbacks) {
98a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mContext = context;
99a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mUserHandle = new UserHandle(userId);
100a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mCallbacks = callbacks;
101a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mClient = new PrintSpoolerClient(this);
102a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mIntent = new Intent();
103a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mIntent.setComponent(new ComponentName("com.android.printspooler",
104a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav                "com.android.printspooler.model.PrintSpoolerService"));
105a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
106a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
107a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
108a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            int appId) {
109a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
110a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
111a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
11285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
113a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
114a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
115a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(),
116a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    componentName, state, appId);
117a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
118a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print jobs.", re);
119a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
120a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print jobs.", te);
12185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
122835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
123835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()");
124835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
12585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
12685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
12785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
12885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
129a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
130a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return null;
131a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
132a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1337bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    public final void createPrintJob(PrintJobInfo printJob) {
134a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
135a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
13785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
138a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
139a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
1407bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            getRemoteInstanceLazy().createPrintJob(printJob);
141a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
142a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error creating print job.", re);
143a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
144a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error creating print job.", te);
14585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
146835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
147835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()");
148835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
14985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
15085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
15185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
15285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
153a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
154a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
155a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1562fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
158a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
159a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
16085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
161a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
162a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
163a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            getRemoteInstanceLazy().writePrintJobData(fd, printJobId);
164a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
165a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error writing print job data.", re);
166a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
167a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error writing print job data.", te);
168a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } finally {
169835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
170835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()");
171835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
172a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            // We passed the file descriptor across and now the other
173a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            // side is responsible to close it, so close the local copy.
174a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            IoUtils.closeQuietly(fd);
17585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
17685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
17785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
17885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
179a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
180a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
181a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
183a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
184a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
185a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
18685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
187a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
188a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
189a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(),
190a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    printJobId, appId);
191a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
192a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print job info.", re);
193a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
194a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print job info.", te);
19585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
196835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
197835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()");
198835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
19985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
20085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
20185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
20285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
203a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
204a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return null;
205a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
206a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
2072fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
208a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
209a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
210a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
21185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
212a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
213a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
214a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(),
2158c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                    printJobId, state, error);
216a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
217a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job state.", re);
218a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
219a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job state.", te);
22085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
221835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
222835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()");
223835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
22485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
22585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
22685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
22785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
228a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
229a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return false;
230a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
231a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
2322fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
233a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
234a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
235a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
23685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
237a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
238a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
239a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(),
240a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    printJobId, tag);
241a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
242a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job tag.", re);
243a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
244a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job tag.", te);
24585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
246835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
247835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()");
248835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
24985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
25085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
25185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
25285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
253a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
254a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return false;
255a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
256a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
257a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public final void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
258a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        throwIfCalledOnMainThread();
259a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        synchronized (mLock) {
260a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            throwIfDestroyedLocked();
261a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            mCanUnbind = false;
262a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
263a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        try {
264a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            getRemoteInstanceLazy().setPrintJobCancelling(printJobId,
265a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    cancelling);
266a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } catch (RemoteException re) {
267a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job cancelling.", re);
268a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } catch (TimeoutException te) {
269a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job cancelling.", te);
270a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } finally {
271a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (DEBUG) {
272a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
273a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        + "] setPrintJobCancelling()");
274a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
275a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            synchronized (mLock) {
276a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mCanUnbind = true;
277a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mLock.notifyAll();
278a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
279a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
280a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
281a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
2822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final void removeObsoletePrintJobs() {
2832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        throwIfCalledOnMainThread();
2842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        synchronized (mLock) {
2852fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            throwIfDestroyedLocked();
2862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            mCanUnbind = false;
2872fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
2882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        try {
2892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            getRemoteInstanceLazy().removeObsoletePrintJobs();
2902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } catch (RemoteException re) {
2912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
2922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } catch (TimeoutException te) {
2932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
2942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } finally {
2952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            if (DEBUG) {
2962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
2972fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        + "] removeObsoletePrintJobs()");
2982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
2992fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            synchronized (mLock) {
3002fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                mCanUnbind = true;
3012fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                mLock.notifyAll();
3022fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
3032fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
3042fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
3052fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
306a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public final void destroy() {
307a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
308a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (DEBUG) {
309a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()");
310a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
311a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
312a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
313a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            unbindLocked();
314a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mDestroyed = true;
31585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
316a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
317a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
318a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
319b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
320b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        synchronized (mLock) {
321b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("destroyed=")
322b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(String.valueOf(mDestroyed)).println();
323b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("bound=")
324b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append((mRemoteInstance != null) ? "true" : "false").println();
325dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
326dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.flush();
327dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
328dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            try {
329dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
330dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            } catch (TimeoutException te) {
331dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                /* ignore */
332dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            } catch (RemoteException re) {
333dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                /* ignore */
334b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
335b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
336b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    }
337b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
338a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void onAllPrintJobsHandled() {
339a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
340a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
341a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            unbindLocked();
342a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
343a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
344a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
345dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private void onPrintJobStateChanged(PrintJobInfo printJob) {
346dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        mCallbacks.onPrintJobStateChanged(printJob);
347704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
348704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
349a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
350a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
351a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mRemoteInstance != null) {
352a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return mRemoteInstance;
353a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
354a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            bindLocked();
355a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mRemoteInstance;
356a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
357a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
358a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
359a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void bindLocked() throws TimeoutException {
3602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (mRemoteInstance != null) {
3612fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
3622fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
363a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (DEBUG) {
364a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
365a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
366a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
367a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mContext.bindServiceAsUser(mIntent, mServiceConnection,
368597945fd3a6b52ac70bb9afc5ec8c59039fffd77Svetoslav                Context.BIND_AUTO_CREATE, mUserHandle);
369a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
370a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final long startMillis = SystemClock.uptimeMillis();
371a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        while (true) {
372a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mRemoteInstance != null) {
373a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                break;
374a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
375a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
376a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
377a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (remainingMillis <= 0) {
378a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                throw new TimeoutException("Cannot get spooler!");
379a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
380a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            try {
381a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mLock.wait(remainingMillis);
382a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } catch (InterruptedException ie) {
383a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                /* ignore */
384a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
385a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
38685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
38785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        mCanUnbind = true;
38885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        mLock.notifyAll();
389a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
390a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
391a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void unbindLocked() {
3922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (mRemoteInstance == null) {
3932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
3942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
39585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        while (true) {
39685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            if (mCanUnbind) {
39785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                if (DEBUG) {
39885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                    Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
39985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                }
40085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                clearClientLocked();
40185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mRemoteInstance = null;
40285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mContext.unbindService(mServiceConnection);
40385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                return;
40485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
40585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            try {
40685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.wait();
40785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            } catch (InterruptedException ie) {
40885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                /* ignore */
40985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
410a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
41185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
412a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
413a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
414a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void setClientLocked() {
415a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
416a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mRemoteInstance.setClient(mClient);
417a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
418a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.d(LOG_TAG, "Error setting print spooler client", re);
419a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
420a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
421a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
422a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void clearClientLocked() {
423a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
424a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mRemoteInstance.setClient(null);
425a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
426a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.d(LOG_TAG, "Error clearing print spooler client", re);
427a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
428a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
429a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
430a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
431a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void throwIfDestroyedLocked() {
432a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (mDestroyed) {
433a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new IllegalStateException("Cannot interact with a destroyed instance.");
434a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
435a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
436a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
437a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void throwIfCalledOnMainThread() {
438a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
439a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new RuntimeException("Cannot invoke on the main thread");
440a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
441a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
442a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
443a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final class MyServiceConnection implements ServiceConnection {
444a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
445a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onServiceConnected(ComponentName name, IBinder service) {
446a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            synchronized (mLock) {
447a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mRemoteInstance = IPrintSpooler.Stub.asInterface(service);
448a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                setClientLocked();
449a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mLock.notifyAll();
450a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
451a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
452a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
453a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
454a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onServiceDisconnected(ComponentName name) {
455a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            synchronized (mLock) {
456a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                clearClientLocked();
457a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mRemoteInstance = null;
458a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
459a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
460a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
461a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
462a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class GetPrintJobInfosCaller
463a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            extends TimedRemoteCaller<List<PrintJobInfo>> {
464a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
465a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
466a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public GetPrintJobInfosCaller() {
467a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
468a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
469a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
470a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) {
471a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(printJobs, sequence);
472a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
473a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
474a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
475a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
476a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target,
477a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                ComponentName componentName, int state, int appId)
478a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        throws RemoteException, TimeoutException {
479a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
480a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.getPrintJobInfos(mCallback, componentName, state, appId, sequence);
481a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
482a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
483a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
484a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
485a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
486a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
487a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
488a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public GetPrintJobInfoCaller() {
489a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
490a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
491a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
492a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
493a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(printJob, sequence);
494a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
495a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
496a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
497a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
4982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
499a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                int appId) throws RemoteException, TimeoutException {
500a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
501a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
502a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
503a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
504a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
505a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
506a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> {
507a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
508a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
509a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public SetPrintJobStateCaller() {
510a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
511a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
512a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
513a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onSetPrintJobStateResult(boolean success, int sequence) {
514a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(success, sequence);
515a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
516a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
517a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
518a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
5192fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
520269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                int status, String error) throws RemoteException, TimeoutException {
521a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
5228c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            target.setPrintJobState(printJobId, status, error, mCallback, sequence);
523a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
524a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
525a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
526a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
527a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> {
528a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
529a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
530a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public SetPrintJobTagCaller() {
531a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
532a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
533a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
534a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onSetPrintJobTagResult(boolean success, int sequence) {
535a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(success, sequence);
536a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
537a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
538a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
539a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
5402fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
541a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                String tag) throws RemoteException, TimeoutException {
542a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
543a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.setPrintJobTag(printJobId, tag, mCallback, sequence);
544a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
545a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
546a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
547a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
548a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static abstract class BasePrintSpoolerServiceCallbacks
549a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            extends IPrintSpoolerCallbacks.Stub {
550a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
551a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) {
552a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
553a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
554a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
555a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
556a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
557a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
558a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
559a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
560a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
561a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onCancelPrintJobResult(boolean canceled, int sequence) {
562a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
563a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
564a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
565a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
566a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onSetPrintJobStateResult(boolean success, int sequece) {
567a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
568a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
569a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
570a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
571a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onSetPrintJobTagResult(boolean success, int sequence) {
572a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
573a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
574a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
575a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
576a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
577a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
578a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final WeakReference<RemotePrintSpooler> mWeakSpooler;
579a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
580a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public PrintSpoolerClient(RemotePrintSpooler spooler) {
581a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler);
582a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
583a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
584a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
585a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onPrintJobQueued(PrintJobInfo printJob) {
586a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
587a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
588a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
589a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
590a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.mCallbacks.onPrintJobQueued(printJob);
591a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
592a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
593a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
594a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
595a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
596a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
597a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
598a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsForServiceHandled(ComponentName printService) {
599a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
600a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
601a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
602a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
603a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService);
604a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
605a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
606a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
607a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
608a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
609a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
610a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
611a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsHandled() {
612a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
613a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
614a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
615a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
616a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.onAllPrintJobsHandled();
617a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
618a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
619a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
620a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
621a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
622704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
623704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        @Override
624dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void onPrintJobStateChanged(PrintJobInfo printJob) {
625704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
626704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (spooler != null) {
627704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final long identity = Binder.clearCallingIdentity();
628704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                try {
629dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    spooler.onPrintJobStateChanged(printJob);
630704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                } finally {
631704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    Binder.restoreCallingIdentity(identity);
632704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
633704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
634704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
635a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
636a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov}
637