blob: 6295822c7e4a2c311aaa374d22a026d5034f3fe3 [file] [log] [blame]
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.printservice;
18
19import android.app.Service;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Looper;
26import android.os.Message;
27import android.os.RemoteException;
28import android.print.PrintJobInfo;
29import android.print.PrinterId;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070030import android.util.Log;
31
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.List;
35
36/**
37 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070038 * This is the base class for implementing print services. A print service knows
39 * how to discover and interact one or more printers via one or more protocols.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070040 * </p>
41 * <h3>Printer discovery</h3>
42 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070043 * A print service is responsible for discovering printers, adding discovered printers,
44 * removing added printers, and updating added printers. When the system is interested
45 * in printers managed by your service it will call {@link
46 * #onCreatePrinterDiscoverySession()} from which you must return a new {@link
47 * PrinterDiscoverySession} instance. The returned session encapsulates the interaction
48 * between the system and your service during printer discovery. For description of this
49 * interaction refer to the documentation for {@link PrinterDiscoverySession}.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070050 * </p>
51 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070052 * For every printer discovery session all printers have to be added since system does
53 * not retain printers across sessions. Hence, each printer known to this print service
54 * should be added only once during a discovery session. Only an already added printer
55 * can be removed or updated. Removed printers can be added again.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070056 * </p>
57 * <h3>Print jobs</h3>
58 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070059 * When a new print job targeted to a printer managed by this print service is is queued,
60 * i.e. ready for processing by the print service, you will receive a call to {@link
61 * #onPrintJobQueued(PrintJob)}. The print service may handle the print job immediately
62 * or schedule that for an appropriate time in the future. The list of all active print
63 * jobs for this service is obtained by calling {@link #getActivePrintJobs()}. Active
64 * print jobs are ones that are queued or started.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070065 * </p>
66 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070067 * A print service is responsible for setting a print job's state as appropriate
68 * while processing it. Initially, a print job is queued, i.e. {@link PrintJob#isQueued()
69 * PrintJob.isQueued()} returns true, which means that the document to be printed is
70 * spooled by the system and the print service can begin processing it. You can obtain
71 * the printed document by calling {@link PrintJob#getDocument() PrintJob.getDocument()}
72 * whose data is accessed via {@link PrintDocument#getData() PrintDocument.getData()}.
73 * After the print service starts printing the data it should set the print job's
74 * state to started by calling {@link PrintJob#start()} after which
75 * {@link PrintJob#isStarted() PrintJob.isStarted()} would return true. Upon successful
76 * completion, the print job should be marked as completed by calling {@link
77 * PrintJob#complete() PrintJob.complete()} after which {@link PrintJob#isCompleted()
78 * PrintJob.isCompleted()} would return true. In case of a failure, the print job should
Svetoslav Ganov3bf79762013-08-20 16:40:13 -070079 * be marked as failed by calling {@link PrintJob#fail(String) PrintJob.fail(
80 * String)} after which {@link PrintJob#isFailed() PrintJob.isFailed()} would
Svetoslav Ganov798bed62013-08-11 12:29:39 -070081 * return true.
Svetoslav Ganova0027152013-06-25 14:59:53 -070082 * </p>
83 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070084 * If a print job is queued or started and the user requests to cancel it, the print
85 * service will receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
86 * requests from the service to do best effort in canceling the job. In case the job
87 * is successfully canceled, its state has to be marked as cancelled by calling {@link
88 * PrintJob#cancel() PrintJob.cancel()} after which {@link PrintJob#isCancelled()
89 * PrintJob.isCacnelled()} would return true.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070090 * </p>
91 * <h3>Lifecycle</h3>
92 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -070093 * The lifecycle of a print service is managed exclusively by the system and follows
94 * the established service lifecycle. Additionally, starting or stopping a print service
95 * is triggered exclusively by an explicit user action through enabling or disabling it
96 * in the device settings. After the system binds to a print service, it calls {@link
97 * #onConnected()}. This method can be overriden by clients to perform post binding setup.
98 * Also after the system unbinds from a print service, it calls {@link #onDisconnected()}.
99 * This method can be overriden by clients to perform post unbinding cleanup. Your should
100 * not do any work after the system disconnected from your print service since the
101 * service can be killed at any time to reclaim memory. The system will not disconnect
102 * from a print service if there are active print jobs for the printers managed by it.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700103 * </p>
104 * <h3>Declaration</h3>
105 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700106 * A print service is declared as any other service in an AndroidManifest.xml but it must
107 * also specify that it handles the {@link android.content.Intent} with action {@link
108 * #SERVICE_INTERFACE android.printservice.PrintService}. Failure to declare this intent
109 * will cause the system to ignore the print service. Additionally, a print service must
110 * request the {@link android.Manifest.permission#BIND_PRINT_SERVICE
111 * android.permission.BIND_PRINT_SERVICE} permission to ensure that only the system can
112 * bind to it. Failure to declare this intent will cause the system to ignore the print
113 * service. Following is an example declaration:
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700114 * </p>
115 * <pre>
116 * &lt;service android:name=".MyPrintService"
117 * android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
118 * &lt;intent-filter&gt;
119 * &lt;action android:name="android.printservice.PrintService" /&gt;
120 * &lt;/intent-filter&gt;
121 * . . .
122 * &lt;/service&gt;
123 * </pre>
124 * <h3>Configuration</h3>
125 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700126 * A print service can be configured by specifying an optional settings activity which
127 * exposes service specific settings, an optional add printers activity which is used for
128 * manual addition of printers, vendor name ,etc. It is a responsibility of the system
129 * to launch the settings and add printers activities when appropriate.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700130 * </p>
131 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700132 * A print service is configured by providing a {@link #SERVICE_META_DATA meta-data}
133 * entry in the manifest when declaring the service. A service declaration with a meta-data
134 * tag is presented below:
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700135 * <pre> &lt;service android:name=".MyPrintService"
136 * android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
137 * &lt;intent-filter&gt;
138 * &lt;action android:name="android.printservice.PrintService" /&gt;
139 * &lt;/intent-filter&gt;
140 * &lt;meta-data android:name="android.printservice" android:resource="@xml/printservice" /&gt;
141 * &lt;/service&gt;</pre>
142 * </p>
143 * <p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700144 * For more details for how to configure your print service via the meta-data refer to
145 * {@link #SERVICE_META_DATA} and <code>&lt;{@link android.R.styleable#PrintService
146 * print-service}&gt;</code>.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700147 * </p>
Svetoslav269403b2013-08-14 17:31:04 -0700148 * <p>
149 * <strong>Note: </strong> All callbacks in this class are executed on the main
150 * application thread. You should also invoke any method of this class on the main
151 * application thread.
152 * </p>
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700153 */
154public abstract class PrintService extends Service {
155
Svetoslav Ganova0027152013-06-25 14:59:53 -0700156 private static final String LOG_TAG = "PrintService";
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700157
Svetoslav Ganovb6699172013-09-07 22:42:47 -0700158 private static final boolean DEBUG = false;
159
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700160 /**
161 * The {@link Intent} action that must be declared as handled by a service
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700162 * in its manifest for the system to recognize it as a print service.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700163 */
164 public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
165
166 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700167 * Name under which a {@link PrintService} component publishes additional information
168 * about itself. This meta-data must reference a XML resource containing a <code>
169 * &lt;{@link android.R.styleable#PrintService print-service}&gt;</code> tag. This is
170 * a sample XML file configuring a print service:
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700171 * <pre> &lt;print-service
Svetoslav Ganova0027152013-06-25 14:59:53 -0700172 * android:vendor="SomeVendor"
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700173 * android:settingsActivity="foo.bar.MySettingsActivity"
174 * andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
175 * . . .
176 * /&gt;</pre>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700177 * <p>
178 * For detailed configuration options that can be specified via the meta-data
179 * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
180 * </p>
Svetoslav Ganov860f8a62013-09-14 00:59:03 -0700181 * <p>
182 * If you declare a settings or add a printers activity, they have to be exported,
183 * by setting the {@link android.R.attr#exported} activity attribute to <code>true
184 * </code>. Also in case you want only the system to be able to start any of these
185 * activities you can specify that they request the android.permission
186 * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
187 * {@link android.R.attr#permission} activity attribute.
188 * </p>
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700189 */
190 public static final String SERVICE_META_DATA = "android.printservice";
191
Svetoslav1c43fce2013-10-16 10:57:48 -0700192 /**
193 * If you declared an optional activity with advanced print options via the
Narayan Kamath0d9ada92015-02-06 13:10:53 +0000194 * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
Svetoslav1c43fce2013-10-16 10:57:48 -0700195 * attribute, this extra is used to pass in the currently constructed {@link
196 * PrintJobInfo} to your activity allowing you to modify it. After you are
197 * done, you must return the modified {@link PrintJobInfo} via the same extra.
198 * <p>
199 * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
200 * should build another one using the {@link PrintJobInfo.Builder} class. You
201 * can specify any standard properties and add advanced, printer specific,
202 * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
Svetoslava798c0a2014-05-15 10:47:19 -0700203 * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
Svetoslav1c43fce2013-10-16 10:57:48 -0700204 * PrintJobInfo.Builder#putAdvancedOption(String, int)
Svetoslava798c0a2014-05-15 10:47:19 -0700205 * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
Svetoslav1c43fce2013-10-16 10:57:48 -0700206 * are not interpreted by the system, they will not be visible to applications,
207 * and can only be accessed by your print service via {@link
208 * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
209 * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
210 * </p>
Svetoslavb4fda132013-10-25 18:57:43 -0700211 * <p>
212 * If the advanced print options activity offers changes to the standard print
213 * options, you can get the current {@link android.print.PrinterInfo} using the
Svetoslava798c0a2014-05-15 10:47:19 -0700214 * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
215 * with UI options supported by the current printer. For example, if the current
216 * printer does not support a given media size, you should not offer it in the
217 * advanced print options UI.
Svetoslavb4fda132013-10-25 18:57:43 -0700218 * </p>
Svetoslava798c0a2014-05-15 10:47:19 -0700219 *
220 * @see #EXTRA_PRINTER_INFO
Svetoslav1c43fce2013-10-16 10:57:48 -0700221 */
222 public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
223
Svetoslava798c0a2014-05-15 10:47:19 -0700224 /**
225 * If you declared an optional activity with advanced print options via the
Narayan Kamath0d9ada92015-02-06 13:10:53 +0000226 * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
Svetoslava798c0a2014-05-15 10:47:19 -0700227 * attribute, this extra is used to pass in the currently selected printer's
228 * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
229 *
230 * @see #EXTRA_PRINT_JOB_INFO
231 */
Svet Ganov8fbd0dc2014-07-14 10:49:40 -0700232 public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
Svetoslava798c0a2014-05-15 10:47:19 -0700233
Svet Ganov5772b5c2015-06-11 02:46:45 -0700234 /**
235 * If you declared an optional activity with advanced print options via the
236 * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
237 * attribute, this extra is used to pass in the meta-data for the currently printed
238 * document as a {@link android.print.PrintDocumentInfo} to your activity allowing
239 * you to inspect it.
240 *
241 * @see #EXTRA_PRINT_JOB_INFO
242 * @see #EXTRA_PRINTER_INFO
243 */
244 public static final String EXTRA_PRINT_DOCUMENT_INFO =
245 "android.printservice.extra.PRINT_DOCUMENT_INFO";
246
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700247 private Handler mHandler;
248
249 private IPrintServiceClient mClient;
250
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700251 private int mLastSessionId = -1;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700252
Svetoslav269403b2013-08-14 17:31:04 -0700253 private PrinterDiscoverySession mDiscoverySession;
254
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700255 @Override
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700256 protected final void attachBaseContext(Context base) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700257 super.attachBaseContext(base);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700258 mHandler = new ServiceHandler(base.getMainLooper());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700259 }
260
261 /**
262 * The system has connected to this service.
263 */
264 protected void onConnected() {
265 /* do nothing */
266 }
267
268 /**
269 * The system has disconnected from this service.
270 */
271 protected void onDisconnected() {
272 /* do nothing */
273 }
274
275 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700276 * Callback asking you to create a new {@link PrinterDiscoverySession}.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700277 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700278 * @see PrinterDiscoverySession
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700279 */
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700280 protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700281
282 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700283 * Called when cancellation of a print job is requested. The service
Svetoslav Ganova0027152013-06-25 14:59:53 -0700284 * should do best effort to fulfill the request. After the cancellation
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700285 * is performed, the print job should be marked as cancelled state by
Svetoslav Ganova0027152013-06-25 14:59:53 -0700286 * calling {@link PrintJob#cancel()}.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700287 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700288 * @param printJob The print job to cancel.
289 *
290 * @see PrintJob#cancel() PrintJob.cancel()
291 * @see PrintJob#isCancelled() PrintJob.isCancelled()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700292 */
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700293 protected abstract void onRequestCancelPrintJob(PrintJob printJob);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700294
295 /**
296 * Called when there is a queued print job for one of the printers
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700297 * managed by this print service.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700298 *
299 * @param printJob The new queued print job.
300 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700301 * @see PrintJob#isQueued() PrintJob.isQueued()
302 * @see #getActivePrintJobs()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700303 */
304 protected abstract void onPrintJobQueued(PrintJob printJob);
305
306 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700307 * Gets the active print jobs for the printers managed by this service.
308 * Active print jobs are ones that are not in a final state, i.e. whose
309 * state is queued or started.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700310 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700311 * @return The active print jobs.
312 *
313 * @see PrintJob#isQueued() PrintJob.isQueued()
314 * @see PrintJob#isStarted() PrintJob.isStarted()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700315 */
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700316 public final List<PrintJob> getActivePrintJobs() {
Svetoslav269403b2013-08-14 17:31:04 -0700317 throwIfNotCalledOnMainThread();
318 if (mClient == null) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700319 return Collections.emptyList();
320 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700321 try {
322 List<PrintJob> printJobs = null;
Svetoslav269403b2013-08-14 17:31:04 -0700323 List<PrintJobInfo> printJobInfos = mClient.getPrintJobInfos();
Svetoslav Ganova0027152013-06-25 14:59:53 -0700324 if (printJobInfos != null) {
325 final int printJobInfoCount = printJobInfos.size();
326 printJobs = new ArrayList<PrintJob>(printJobInfoCount);
327 for (int i = 0; i < printJobInfoCount; i++) {
Svetoslav269403b2013-08-14 17:31:04 -0700328 printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
Svetoslav Ganova0027152013-06-25 14:59:53 -0700329 }
330 }
331 if (printJobs != null) {
332 return printJobs;
333 }
334 } catch (RemoteException re) {
335 Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
336 }
337 return Collections.emptyList();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700338 }
339
340 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700341 * Generates a global printer id given the printer's locally unique one.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700342 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700343 * @param localId A locally unique id in the context of your print service.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700344 * @return Global printer id.
345 */
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700346 public final PrinterId generatePrinterId(String localId) {
Svetoslav269403b2013-08-14 17:31:04 -0700347 throwIfNotCalledOnMainThread();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700348 return new PrinterId(new ComponentName(getPackageName(),
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700349 getClass().getName()), localId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700350 }
351
Svetoslav269403b2013-08-14 17:31:04 -0700352 static void throwIfNotCalledOnMainThread() {
353 if (!Looper.getMainLooper().isCurrentThread()) {
354 throw new IllegalAccessError("must be called from the main thread");
355 }
356 }
357
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700358 @Override
359 public final IBinder onBind(Intent intent) {
360 return new IPrintService.Stub() {
361 @Override
Svetoslav269403b2013-08-14 17:31:04 -0700362 public void createPrinterDiscoverySession() {
363 mHandler.sendEmptyMessage(ServiceHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700364 }
365
366 @Override
Svetoslav269403b2013-08-14 17:31:04 -0700367 public void destroyPrinterDiscoverySession() {
368 mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
369 }
370
371 public void startPrinterDiscovery(List<PrinterId> priorityList) {
372 mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
373 priorityList).sendToTarget();
374 }
375
376 @Override
377 public void stopPrinterDiscovery() {
378 mHandler.sendEmptyMessage(ServiceHandler.MSG_STOP_PRINTER_DISCOVERY);
379 }
380
381 @Override
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700382 public void validatePrinters(List<PrinterId> printerIds) {
383 mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
384 printerIds).sendToTarget();
385 }
386
387 @Override
388 public void startPrinterStateTracking(PrinterId printerId) {
389 mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
390 printerId).sendToTarget();
391 }
392
393 @Override
394 public void stopPrinterStateTracking(PrinterId printerId) {
395 mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
Svetoslav269403b2013-08-14 17:31:04 -0700396 printerId).sendToTarget();
397 }
398
399 @Override
400 public void setClient(IPrintServiceClient client) {
jangwon.leeeae626f2014-02-06 11:13:24 +0900401 mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client)
Svetoslav269403b2013-08-14 17:31:04 -0700402 .sendToTarget();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700403 }
404
405 @Override
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700406 public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
407 mHandler.obtainMessage(ServiceHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
Svetoslav Ganova0027152013-06-25 14:59:53 -0700408 printJobInfo).sendToTarget();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700409 }
410
411 @Override
Svetoslav Ganova0027152013-06-25 14:59:53 -0700412 public void onPrintJobQueued(PrintJobInfo printJobInfo) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700413 mHandler.obtainMessage(ServiceHandler.MSG_ON_PRINTJOB_QUEUED,
Svetoslav Ganova0027152013-06-25 14:59:53 -0700414 printJobInfo).sendToTarget();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700415 }
416 };
417 }
418
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700419 private final class ServiceHandler extends Handler {
Svetoslav269403b2013-08-14 17:31:04 -0700420 public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
421 public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
422 public static final int MSG_START_PRINTER_DISCOVERY = 3;
423 public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700424 public static final int MSG_VALIDATE_PRINTERS = 5;
425 public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
426 public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
427 public static final int MSG_ON_PRINTJOB_QUEUED = 8;
428 public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
jangwon.leeeae626f2014-02-06 11:13:24 +0900429 public static final int MSG_SET_CLIENT = 10;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700430
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700431 public ServiceHandler(Looper looper) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700432 super(looper, null, true);
433 }
434
435 @Override
Svetoslav269403b2013-08-14 17:31:04 -0700436 @SuppressWarnings("unchecked")
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700437 public void handleMessage(Message message) {
438 final int action = message.what;
439 switch (action) {
Svetoslav269403b2013-08-14 17:31:04 -0700440 case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
Svetoslavb5f18062013-09-23 18:48:34 -0700441 if (DEBUG) {
442 Log.i(LOG_TAG, "MSG_CREATE_PRINTER_DISCOVERY_SESSION "
443 + getPackageName());
444 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700445 PrinterDiscoverySession session = onCreatePrinterDiscoverySession();
446 if (session == null) {
447 throw new NullPointerException("session cannot be null");
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700448 }
Svetoslav269403b2013-08-14 17:31:04 -0700449 if (session.getId() == mLastSessionId) {
450 throw new IllegalStateException("cannot reuse session instances");
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700451 }
Svetoslav269403b2013-08-14 17:31:04 -0700452 mDiscoverySession = session;
453 mLastSessionId = session.getId();
454 session.setObserver(mClient);
455 } break;
456
457 case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
Svetoslavb5f18062013-09-23 18:48:34 -0700458 if (DEBUG) {
459 Log.i(LOG_TAG, "MSG_DESTROY_PRINTER_DISCOVERY_SESSION "
460 + getPackageName());
461 }
Svetoslav269403b2013-08-14 17:31:04 -0700462 if (mDiscoverySession != null) {
463 mDiscoverySession.destroy();
464 mDiscoverySession = null;
465 }
466 } break;
467
468 case MSG_START_PRINTER_DISCOVERY: {
Svetoslavb5f18062013-09-23 18:48:34 -0700469 if (DEBUG) {
470 Log.i(LOG_TAG, "MSG_START_PRINTER_DISCOVERY "
471 + getPackageName());
472 }
Svetoslav269403b2013-08-14 17:31:04 -0700473 if (mDiscoverySession != null) {
474 List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
475 mDiscoverySession.startPrinterDiscovery(priorityList);
476 }
477 } break;
478
479 case MSG_STOP_PRINTER_DISCOVERY: {
Svetoslavb5f18062013-09-23 18:48:34 -0700480 if (DEBUG) {
481 Log.i(LOG_TAG, "MSG_STOP_PRINTER_DISCOVERY "
482 + getPackageName());
483 }
Svetoslav269403b2013-08-14 17:31:04 -0700484 if (mDiscoverySession != null) {
485 mDiscoverySession.stopPrinterDiscovery();
486 }
487 } break;
488
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700489 case MSG_VALIDATE_PRINTERS: {
Svetoslavb5f18062013-09-23 18:48:34 -0700490 if (DEBUG) {
491 Log.i(LOG_TAG, "MSG_VALIDATE_PRINTERS "
492 + getPackageName());
493 }
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700494 if (mDiscoverySession != null) {
495 List<PrinterId> printerIds = (List<PrinterId>) message.obj;
496 mDiscoverySession.validatePrinters(printerIds);
497 }
498 } break;
499
500 case MSG_START_PRINTER_STATE_TRACKING: {
Svetoslavb5f18062013-09-23 18:48:34 -0700501 if (DEBUG) {
502 Log.i(LOG_TAG, "MSG_START_PRINTER_STATE_TRACKING "
503 + getPackageName());
504 }
Svetoslav269403b2013-08-14 17:31:04 -0700505 if (mDiscoverySession != null) {
506 PrinterId printerId = (PrinterId) message.obj;
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700507 mDiscoverySession.startPrinterStateTracking(printerId);
508 }
509 } break;
510
511 case MSG_STOP_PRINTER_STATE_TRACKING: {
Svetoslavb5f18062013-09-23 18:48:34 -0700512 if (DEBUG) {
513 Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
514 + getPackageName());
515 }
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700516 if (mDiscoverySession != null) {
517 PrinterId printerId = (PrinterId) message.obj;
518 mDiscoverySession.stopPrinterStateTracking(printerId);
Svetoslav269403b2013-08-14 17:31:04 -0700519 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700520 } break;
521
Svetoslav Ganov55b409a2013-07-31 17:25:13 -0700522 case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
Svetoslavb5f18062013-09-23 18:48:34 -0700523 if (DEBUG) {
524 Log.i(LOG_TAG, "MSG_ON_REQUEST_CANCEL_PRINTJOB "
525 + getPackageName());
526 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700527 PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
528 onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700529 } break;
530
Svetoslav Ganov55b409a2013-07-31 17:25:13 -0700531 case MSG_ON_PRINTJOB_QUEUED: {
Svetoslavb5f18062013-09-23 18:48:34 -0700532 if (DEBUG) {
533 Log.i(LOG_TAG, "MSG_ON_PRINTJOB_QUEUED "
534 + getPackageName());
535 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700536 PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
Svetoslav Ganovb6699172013-09-07 22:42:47 -0700537 if (DEBUG) {
538 Log.i(LOG_TAG, "Queued: " + printJobInfo);
539 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700540 onPrintJobQueued(new PrintJob(printJobInfo, mClient));
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700541 } break;
542
jangwon.leeeae626f2014-02-06 11:13:24 +0900543 case MSG_SET_CLIENT: {
Svetoslavb5f18062013-09-23 18:48:34 -0700544 if (DEBUG) {
jangwon.leeeae626f2014-02-06 11:13:24 +0900545 Log.i(LOG_TAG, "MSG_SET_CLIENT "
Svetoslavb5f18062013-09-23 18:48:34 -0700546 + getPackageName());
547 }
Svetoslav269403b2013-08-14 17:31:04 -0700548 mClient = (IPrintServiceClient) message.obj;
549 if (mClient != null) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700550 onConnected();
551 } else {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700552 onDisconnected();
Svetoslav269403b2013-08-14 17:31:04 -0700553 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700554 } break;
555
556 default: {
557 throw new IllegalArgumentException("Unknown message: " + action);
558 }
559 }
560 }
561 }
562}