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;
24a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.IBinder;
25a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.ParcelFileDescriptor;
26a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.RemoteException;
27a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.SystemClock;
28a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.os.UserHandle;
29a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpooler;
30a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerCallbacks;
31a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintSpoolerClient;
322fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
33a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.PrintJobInfo;
34a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.Slog;
35a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.TimedRemoteCaller;
36a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
37b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.FileDescriptor;
38b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.PrintWriter;
39a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.lang.ref.WeakReference;
40a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.List;
41a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.util.concurrent.TimeoutException;
42a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport libcore.io.IoUtils;
442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
45a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov/**
46a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * This represents the remote print spooler as a local object to the
47a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * PrintManagerSerivce. It is responsible to connecting to the remote
48a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * spooler if needed, to make the timed remote calls, to handle
49a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * remote exceptions, and to bind/unbind to the remote instance as
50a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * needed.
51a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov */
52a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovfinal class RemotePrintSpooler {
53a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
54a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final String LOG_TAG = "RemotePrintSpooler";
55a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
56c6066799ad130140159230d14451b429eb828755Svetoslav    private static final boolean DEBUG = false;
57a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
58a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
59a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
60a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Object mLock = new Object();
61a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
62a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
63a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
64a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
65a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
66a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
67a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
68a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
69a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
70a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final ServiceConnection mServiceConnection = new MyServiceConnection();
71a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
72a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Context mContext;
73a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
74a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final UserHandle mUserHandle;
75a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
76a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final PrintSpoolerClient mClient;
77a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
78a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final Intent mIntent;
79a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
80a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final PrintSpoolerCallbacks mCallbacks;
81a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private IPrintSpooler mRemoteInstance;
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private boolean mDestroyed;
85a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
8685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov    private boolean mCanUnbind;
8785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
88a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public static interface PrintSpoolerCallbacks {
89a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onPrintJobQueued(PrintJobInfo printJob);
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsForServiceHandled(ComponentName printService);
91dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void onPrintJobStateChanged(PrintJobInfo printJob);
92a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
93a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
94a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public RemotePrintSpooler(Context context, int userId,
95a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            PrintSpoolerCallbacks callbacks) {
96a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mContext = context;
97a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mUserHandle = new UserHandle(userId);
98a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mCallbacks = callbacks;
99a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mClient = new PrintSpoolerClient(this);
100a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mIntent = new Intent();
101a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mIntent.setComponent(new ComponentName("com.android.printspooler",
102a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                "com.android.printspooler.PrintSpoolerService"));
103a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
104a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
105a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
106a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            int appId) {
107a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
108a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
109a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
11085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
111a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
112a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
113a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(),
114a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    componentName, state, appId);
115a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
116a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print jobs.", re);
117a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
118a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print jobs.", te);
11985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
120835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
121835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()");
122835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
12385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
12485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
12585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
12685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
127a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
128a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return null;
129a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
130a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1317bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    public final void createPrintJob(PrintJobInfo printJob) {
132a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
133a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
134a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
13585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
137a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
1387bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            getRemoteInstanceLazy().createPrintJob(printJob);
139a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
140a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error creating print job.", re);
141a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
142a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error creating print job.", te);
14385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
144835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
145835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()");
146835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
14785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
14885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
14985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
15085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
151a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
152a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
153a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
155a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
15885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
159a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
160a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
161a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            getRemoteInstanceLazy().writePrintJobData(fd, printJobId);
162a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
163a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error writing print job data.", re);
164a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
165a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error writing print job data.", te);
166a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } finally {
167835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
168835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()");
169835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
170a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            // We passed the file descriptor across and now the other
171a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            // side is responsible to close it, so close the local copy.
172a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            IoUtils.closeQuietly(fd);
17385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
17485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
17585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
17685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
177a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
178a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
179a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
181a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
182a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
183a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
18485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
185a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
186a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
187a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(),
188a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    printJobId, appId);
189a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
190a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print job info.", re);
191a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
192a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error getting print job info.", te);
19385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
194835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
195835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()");
196835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
19785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
19885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
19985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
20085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
201a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
202a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return null;
203a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
204a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
2052fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
206a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
207a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
208a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
20985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
210a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
211a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
212a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(),
2138c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                    printJobId, state, error);
214a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
215a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job state.", re);
216a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
217a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job state.", te);
21885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
219835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
220835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()");
221835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
22285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
22385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
22485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
22585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
226a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
227a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return false;
228a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
229a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
2302fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
231a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
232a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
233a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
23485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
235a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
236a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
237a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(),
238a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    printJobId, tag);
239a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
240a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job tag.", re);
241a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (TimeoutException te) {
242a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job tag.", te);
24385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        } finally {
244835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            if (DEBUG) {
245835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()");
246835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }
24785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            synchronized (mLock) {
24885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mCanUnbind = true;
24985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.notifyAll();
25085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
251a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
252a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return false;
253a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
254a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
255a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public final void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
256a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        throwIfCalledOnMainThread();
257a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        synchronized (mLock) {
258a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            throwIfDestroyedLocked();
259a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            mCanUnbind = false;
260a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
261a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        try {
262a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            getRemoteInstanceLazy().setPrintJobCancelling(printJobId,
263a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    cancelling);
264a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } catch (RemoteException re) {
265a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job cancelling.", re);
266a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } catch (TimeoutException te) {
267a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            Slog.e(LOG_TAG, "Error setting print job cancelling.", te);
268a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } finally {
269a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (DEBUG) {
270a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
271a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        + "] setPrintJobCancelling()");
272a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
273a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            synchronized (mLock) {
274a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mCanUnbind = true;
275a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                mLock.notifyAll();
276a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
277a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
278a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
279a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
2802fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public final void removeObsoletePrintJobs() {
2812fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        throwIfCalledOnMainThread();
2822fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        synchronized (mLock) {
2832fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            throwIfDestroyedLocked();
2842fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            mCanUnbind = false;
2852fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
2862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        try {
2872fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            getRemoteInstanceLazy().removeObsoletePrintJobs();
2882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } catch (RemoteException re) {
2892fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
2902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } catch (TimeoutException te) {
2912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
2922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        } finally {
2932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            if (DEBUG) {
2942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
2952fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                        + "] removeObsoletePrintJobs()");
2962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
2972fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            synchronized (mLock) {
2982fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                mCanUnbind = true;
2992fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                mLock.notifyAll();
3002fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
3012fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
3022fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
3032fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
304a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public final void destroy() {
305a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        throwIfCalledOnMainThread();
306a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (DEBUG) {
307a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()");
308a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
309a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
310a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
311a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            unbindLocked();
312a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mDestroyed = true;
31385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mCanUnbind = false;
314a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
315a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
316a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
317b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
318b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        synchronized (mLock) {
319b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("destroyed=")
320b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append(String.valueOf(mDestroyed)).println();
321b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.append(prefix).append("bound=")
322b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    .append((mRemoteInstance != null) ? "true" : "false").println();
323dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
324dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            pw.flush();
325dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov
326dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            try {
327dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
328dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            } catch (TimeoutException te) {
329dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                /* ignore */
330dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov            } catch (RemoteException re) {
331dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                /* ignore */
332b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
333b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
334b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    }
335b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
336a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void onAllPrintJobsHandled() {
337a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
338a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throwIfDestroyedLocked();
339a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            unbindLocked();
340a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
341a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
342a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
343dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov    private void onPrintJobStateChanged(PrintJobInfo printJob) {
344dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        mCallbacks.onPrintJobStateChanged(printJob);
345704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
346704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
347a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
348a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
349a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mRemoteInstance != null) {
350a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return mRemoteInstance;
351a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
352a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            bindLocked();
353a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mRemoteInstance;
354a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
355a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
356a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
357a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void bindLocked() throws TimeoutException {
3582fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (mRemoteInstance != null) {
3592fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
3602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
361a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (DEBUG) {
362a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
363a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
364a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
365a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mContext.bindServiceAsUser(mIntent, mServiceConnection,
366597945fd3a6b52ac70bb9afc5ec8c59039fffd77Svetoslav                Context.BIND_AUTO_CREATE, mUserHandle);
367a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
368a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final long startMillis = SystemClock.uptimeMillis();
369a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        while (true) {
370a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (mRemoteInstance != null) {
371a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                break;
372a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
373a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
374a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
375a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (remainingMillis <= 0) {
376a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                throw new TimeoutException("Cannot get spooler!");
377a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
378a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            try {
379a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mLock.wait(remainingMillis);
380a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } catch (InterruptedException ie) {
381a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                /* ignore */
382a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
383a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
38485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
38585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        mCanUnbind = true;
38685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        mLock.notifyAll();
387a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
388a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
389a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void unbindLocked() {
3902fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (mRemoteInstance == null) {
3912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return;
3922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
39385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov        while (true) {
39485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            if (mCanUnbind) {
39585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                if (DEBUG) {
39685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                    Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
39785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                }
39885b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                clearClientLocked();
39985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mRemoteInstance = null;
40085b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mContext.unbindService(mServiceConnection);
40185b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                return;
40285b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
40385b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            try {
40485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                mLock.wait();
40585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            } catch (InterruptedException ie) {
40685b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov                /* ignore */
40785b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            }
408a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
40985b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov
410a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
411a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
412a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void setClientLocked() {
413a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
414a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mRemoteInstance.setClient(mClient);
415a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
416a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.d(LOG_TAG, "Error setting print spooler client", re);
417a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
418a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
419a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
420a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void clearClientLocked() {
421a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
422a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mRemoteInstance.setClient(null);
423a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
424a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Slog.d(LOG_TAG, "Error clearing print spooler client", re);
425a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
426a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
427a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
428a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
429a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void throwIfDestroyedLocked() {
430a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (mDestroyed) {
431a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new IllegalStateException("Cannot interact with a destroyed instance.");
432a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
433a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
434a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
435a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void throwIfCalledOnMainThread() {
436a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
437a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new RuntimeException("Cannot invoke on the main thread");
438a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
439a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
440a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
441a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final class MyServiceConnection implements ServiceConnection {
442a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
443a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onServiceConnected(ComponentName name, IBinder service) {
444a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            synchronized (mLock) {
445a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mRemoteInstance = IPrintSpooler.Stub.asInterface(service);
446a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                setClientLocked();
447a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mLock.notifyAll();
448a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
449a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
450a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
451a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
452a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onServiceDisconnected(ComponentName name) {
453a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            synchronized (mLock) {
454a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                clearClientLocked();
455a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mRemoteInstance = null;
456a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
457a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
458a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
459a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
460a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class GetPrintJobInfosCaller
461a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            extends TimedRemoteCaller<List<PrintJobInfo>> {
462a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
463a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
464a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public GetPrintJobInfosCaller() {
465a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
466a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
467a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
468a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) {
469a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(printJobs, sequence);
470a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
471a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
472a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
473a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
474a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target,
475a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                ComponentName componentName, int state, int appId)
476a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        throws RemoteException, TimeoutException {
477a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
478a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.getPrintJobInfos(mCallback, componentName, state, appId, sequence);
479a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
480a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
481a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
482a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
483a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
484a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
485a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
486a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public GetPrintJobInfoCaller() {
487a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
488a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
489a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
490a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
491a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(printJob, sequence);
492a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
493a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
494a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
495a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
4962fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
497a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                int appId) throws RemoteException, TimeoutException {
498a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
499a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
500a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
501a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
502a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
503a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
504a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> {
505a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
506a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
507a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public SetPrintJobStateCaller() {
508a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
509a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
510a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
511a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onSetPrintJobStateResult(boolean success, int sequence) {
512a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(success, sequence);
513a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
514a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
515a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
516a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
5172fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
518269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                int status, String error) throws RemoteException, TimeoutException {
519a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
5208c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            target.setPrintJobState(printJobId, status, error, mCallback, sequence);
521a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
522a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
523a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
524a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
525a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> {
526a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IPrintSpoolerCallbacks mCallback;
527a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
528a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public SetPrintJobTagCaller() {
529a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
530a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mCallback = new BasePrintSpoolerServiceCallbacks() {
531a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                @Override
532a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                public void onSetPrintJobTagResult(boolean success, int sequence) {
533a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRemoteMethodResult(success, sequence);
534a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
535a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            };
536a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
537a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
5382fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
539a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                String tag) throws RemoteException, TimeoutException {
540a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            final int sequence = onBeforeRemoteCall();
541a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            target.setPrintJobTag(printJobId, tag, mCallback, sequence);
542a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return getResultTimed(sequence);
543a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
544a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
545a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
546a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static abstract class BasePrintSpoolerServiceCallbacks
547a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            extends IPrintSpoolerCallbacks.Stub {
548a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
549a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) {
550a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
551a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
552a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
553a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
554a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
555a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
556a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
557a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
558a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
559a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onCancelPrintJobResult(boolean canceled, int sequence) {
560a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
561a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
562a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
563a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
564a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onSetPrintJobStateResult(boolean success, int sequece) {
565a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
566a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
567a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
568a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
569a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onSetPrintJobTagResult(boolean success, int sequence) {
570a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            /* do nothing */
571a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
572a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
573a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
574a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
575a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
576a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final WeakReference<RemotePrintSpooler> mWeakSpooler;
577a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
578a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public PrintSpoolerClient(RemotePrintSpooler spooler) {
579a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler);
580a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
581a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
582a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
583a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onPrintJobQueued(PrintJobInfo printJob) {
584a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
585a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
586a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
587a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
588a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.mCallbacks.onPrintJobQueued(printJob);
589a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
590a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
591a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
592a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
593a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
594a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
595a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
596a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsForServiceHandled(ComponentName printService) {
597a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
598a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
599a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
600a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
601a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService);
602a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
603a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
604a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
605a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
606a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
607a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
608a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
609a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onAllPrintJobsHandled() {
610a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
611a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (spooler != null) {
612a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final long identity = Binder.clearCallingIdentity();
613a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                try {
614a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    spooler.onAllPrintJobsHandled();
615a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } finally {
616a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Binder.restoreCallingIdentity(identity);
617a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
618a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
619a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
620704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
621704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        @Override
622dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov        public void onPrintJobStateChanged(PrintJobInfo printJob) {
623704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            RemotePrintSpooler spooler = mWeakSpooler.get();
624704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            if (spooler != null) {
625704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                final long identity = Binder.clearCallingIdentity();
626704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                try {
627dd68da2741fa63070d5ad206020dcccb9f429a5aSvetoslav Ganov                    spooler.onPrintJobStateChanged(printJob);
628704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                } finally {
629704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                    Binder.restoreCallingIdentity(identity);
630704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                }
631704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            }
632704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
633a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
634a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov}
635