14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/*
24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License.
64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at
74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and
144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License.
154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage android.printservice;
184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
191c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslavimport android.R;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Service;
214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName;
224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Context;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Handler;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.IBinder;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Looper;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException;
294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo;
304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrinterId;
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.ArrayList;
344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Collections;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.List;
364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
39798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * This is the base class for implementing print services. A print service knows
40798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * how to discover and interact one or more printers via one or more protocols.
414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Printer discovery</h3>
434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
44798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is responsible for discovering printers, adding discovered printers,
45798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * removing added printers, and updating added printers. When the system is interested
46798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * in printers managed by your service it will call {@link
47798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onCreatePrinterDiscoverySession()} from which you must return a new {@link
48798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrinterDiscoverySession} instance. The returned session encapsulates the interaction
49798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * between the system and your service during printer discovery. For description of this
50798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * interaction refer to the documentation for {@link PrinterDiscoverySession}.
514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
53798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * For every printer discovery session all printers have to be added since system does
54798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * not retain printers across sessions. Hence, each printer known to this print service
55798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * should be added only once during a discovery session. Only an already added printer
56798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * can be removed or updated. Removed printers can be added again.
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Print jobs</h3>
594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
60798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * When a new print job targeted to a printer managed by this print service is is queued,
61798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * i.e. ready for processing by the print service, you will receive a call to {@link
62798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onPrintJobQueued(PrintJob)}. The print service may handle the print job immediately
63798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * or schedule that for an appropriate time in the future. The list of all active print
64798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * jobs for this service is obtained by calling {@link #getActivePrintJobs()}. Active
65798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * print jobs are ones that are queued or started.
664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
68798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is responsible for setting a print job's state as appropriate
69798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * while processing it. Initially, a print job is queued, i.e. {@link PrintJob#isQueued()
70798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isQueued()} returns true, which means that the document to be printed is
71798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * spooled by the system and the print service can begin processing it. You can obtain
72798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * the printed document by calling {@link PrintJob#getDocument() PrintJob.getDocument()}
73798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * whose data is accessed via {@link PrintDocument#getData() PrintDocument.getData()}.
74798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * After the print service starts printing the data it should set the print job's
75798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * state to started by calling {@link PrintJob#start()} after which
76798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * {@link PrintJob#isStarted() PrintJob.isStarted()} would return true. Upon successful
77798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * completion, the print job should be marked as completed by calling {@link
78798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob#complete() PrintJob.complete()} after which {@link PrintJob#isCompleted()
79798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isCompleted()} would return true. In case of a failure, the print job should
803bf7976e78d69310b67f4f19f49b2eb839252b67Svetoslav Ganov * be marked as failed by calling {@link PrintJob#fail(String) PrintJob.fail(
813bf7976e78d69310b67f4f19f49b2eb839252b67Svetoslav Ganov * String)} after which {@link PrintJob#isFailed() PrintJob.isFailed()} would
82798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * return true.
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * </p>
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * <p>
85798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * If a print job is queued or started and the user requests to cancel it, the print
86798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service will receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
87798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * requests from the service to do best effort in canceling the job. In case the job
88798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * is successfully canceled, its state has to be marked as cancelled by calling {@link
89798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob#cancel() PrintJob.cancel()} after which {@link PrintJob#isCancelled()
90798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isCacnelled()} would return true.
914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Lifecycle</h3>
934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
94798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * The lifecycle of a print service is managed exclusively by the system and follows
95798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * the established service lifecycle. Additionally, starting or stopping a print service
96798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * is triggered exclusively by an explicit user action through enabling or disabling it
97798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * in the device settings. After the system binds to a print service, it calls {@link
98798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onConnected()}. This method can be overriden by clients to perform post binding setup.
99798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * Also after the system unbinds from a print service, it calls {@link #onDisconnected()}.
100798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * This method can be overriden by clients to perform post unbinding cleanup. Your should
101798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * not do any work after the system disconnected from your print service since the
102798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service can be killed at any time to reclaim memory. The system will not disconnect
103798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * from a print service if there are active print jobs for the printers managed by it.
1044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Declaration</h3>
1064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
107798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is declared as any other service in an AndroidManifest.xml but it must
108798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * also specify that it handles the {@link android.content.Intent} with action {@link
109798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #SERVICE_INTERFACE android.printservice.PrintService}. Failure to declare this intent
110798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * will cause the system to ignore the print service. Additionally, a print service must
111798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * request the {@link android.Manifest.permission#BIND_PRINT_SERVICE
112798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * android.permission.BIND_PRINT_SERVICE} permission to ensure that only the system can
113798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * bind to it. Failure to declare this intent will cause the system to ignore the print
114798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service. Following is an example declaration:
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <pre>
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;service android:name=".MyPrintService"
1184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
1194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;intent-filter&gt;
1204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         &lt;action android:name="android.printservice.PrintService" /&gt;
1214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;/intent-filter&gt;
1224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     . . .
1234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;/service&gt;
1244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </pre>
1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Configuration</h3>
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
127798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service can be configured by specifying an optional settings activity which
128798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * exposes service specific settings, an optional add printers activity which is used for
129798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * manual addition of printers, vendor name ,etc. It is a responsibility of the system
130798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * to launch the settings and add printers activities when appropriate.
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
133798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is configured by providing a {@link #SERVICE_META_DATA meta-data}
134798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * entry in the manifest when declaring the service. A service declaration with a meta-data
135798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * tag is presented below:
1364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <pre> &lt;service android:name=".MyPrintService"
1374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
1384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;intent-filter&gt;
1394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         &lt;action android:name="android.printservice.PrintService" /&gt;
1404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;/intent-filter&gt;
1414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;meta-data android:name="android.printservice" android:resource="@xml/printservice" /&gt;
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;/service&gt;</pre>
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
145798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * For more details for how to configure your print service via the meta-data refer to
146798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * {@link #SERVICE_META_DATA} and <code>&lt;{@link android.R.styleable#PrintService
147798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * print-service}&gt;</code>.
1484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
149269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * <p>
150269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * <strong>Note: </strong> All callbacks in this class are executed on the main
151269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * application thread. You should also invoke any method of this class on the main
152269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * application thread.
153269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * </p>
1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
1554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic abstract class PrintService extends Service {
1564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final String LOG_TAG = "PrintService";
1584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
159b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    private static final boolean DEBUG = false;
160b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
1624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The {@link Intent} action that must be declared as handled by a service
163798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * in its manifest for the system to recognize it as a print service.
1644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
1664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
168798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Name under which a {@link PrintService} component publishes additional information
169798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * about itself. This meta-data must reference a XML resource containing a <code>
170798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * &lt;{@link android.R.styleable#PrintService print-service}&gt;</code> tag. This is
171798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * a sample XML file configuring a print service:
1724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * <pre> &lt;print-service
173a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     *     android:vendor="SomeVendor"
1744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     android:settingsActivity="foo.bar.MySettingsActivity"
1754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
1764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     . . .
1774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * /&gt;</pre>
178798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * <p>
179798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * For detailed configuration options that can be specified via the meta-data
180798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
181798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * </p>
182860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * <p>
183860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * If you declare a settings or add a printers activity, they have to be exported,
184860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * by setting the {@link android.R.attr#exported} activity attribute to <code>true
185860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * </code>. Also in case you want only the system to be able to start any of these
186860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * activities you can specify that they request the android.permission
187860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
188860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * {@link android.R.attr#permission} activity attribute.
189860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * </p>
1904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String SERVICE_META_DATA = "android.printservice";
1924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1931c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav    /**
1941c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * If you declared an optional activity with advanced print options via the
1951c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
1961c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * attribute, this extra is used to pass in the currently constructed {@link
1971c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo} to your activity allowing you to modify it. After you are
1981c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * done, you must return the modified {@link PrintJobInfo} via the same extra.
1991c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * <p>
2001c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
2011c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * should build another one using the {@link PrintJobInfo.Builder} class. You
2021c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * can specify any standard properties and add advanced, printer specific,
2031c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
2041c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo.Builder#putAdvancedOption(String, String)} and {@link
2051c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo.Builder#putAdvancedOption(String, int)
2061c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo.Builder#putAdvancedOption(String, int)}. The advanced options
2071c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * are not interpreted by the system, they will not be visible to applications,
2081c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * and can only be accessed by your print service via {@link
2091c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
2101c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
2111c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * </p>
212b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * <p>
213b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * If the advanced print options activity offers changes to the standard print
214b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * options, you can get the current {@link android.print.PrinterInfo} using the
215b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * "android.intent.extra.print.EXTRA_PRINTER_INFO" extra which will allow you to
216b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * present the user with UI options supported by the current printer. For example,
217b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * if the current printer does not support a give media size, you should not
218b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * offer it in the advanced print options dialog.
219b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * </p>
2201c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     */
2211c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav    public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
2221c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav
2234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private Handler mHandler;
2244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private IPrintServiceClient mClient;
2264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
227798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private int mLastSessionId = -1;
2284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
229269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private PrinterDiscoverySession mDiscoverySession;
230269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
2314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
232798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected final void attachBaseContext(Context base) {
2334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        super.attachBaseContext(base);
234798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        mHandler = new ServiceHandler(base.getMainLooper());
2354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The system has connected to this service.
2394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
2404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected void onConnected() {
2414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        /* do nothing */
2424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The system has disconnected from this service.
2464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
2474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected void onDisconnected() {
2484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        /* do nothing */
2494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
252798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Callback asking you to create a new {@link PrinterDiscoverySession}.
2534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
254798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrinterDiscoverySession
2554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
256798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
2574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
259798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Called when cancellation of a print job is requested. The service
260a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * should do best effort to fulfill the request. After the cancellation
261798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * is performed, the print job should be marked as cancelled state by
262a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * calling {@link PrintJob#cancel()}.
2634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
264798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param printJob The print job to cancel.
265798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
266798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#cancel() PrintJob.cancel()
267798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isCancelled() PrintJob.isCancelled()
2684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
269798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected abstract void onRequestCancelPrintJob(PrintJob printJob);
2704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Called when there is a queued print job for one of the printers
273798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * managed by this print service.
2744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
2754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param printJob The new queued print job.
2764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
277798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isQueued() PrintJob.isQueued()
278798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see #getActivePrintJobs()
2794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
2804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected abstract void onPrintJobQueued(PrintJob printJob);
2814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
283798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Gets the active print jobs for the printers managed by this service.
284798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Active print jobs are ones that are not in a final state, i.e. whose
285798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * state is queued or started.
2864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
287798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @return The active print jobs.
288798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
289798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isQueued() PrintJob.isQueued()
290798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isStarted() PrintJob.isStarted()
2914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
292798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public final List<PrintJob> getActivePrintJobs() {
293269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        throwIfNotCalledOnMainThread();
294269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (mClient == null) {
295a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return Collections.emptyList();
296a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
297a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
298a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            List<PrintJob> printJobs = null;
299269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            List<PrintJobInfo> printJobInfos = mClient.getPrintJobInfos();
300a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (printJobInfos != null) {
301a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final int printJobInfoCount = printJobInfos.size();
302a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                printJobs = new ArrayList<PrintJob>(printJobInfoCount);
303a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                for (int i = 0; i < printJobInfoCount; i++) {
304269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
3054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
3064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
307a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (printJobs != null) {
308a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return printJobs;
309a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
310a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
311a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
3124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
313a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return Collections.emptyList();
3144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
317798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Generates a global printer id given the printer's locally unique one.
3184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
319798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param localId A locally unique id in the context of your print service.
3204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @return Global printer id.
3214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
322798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public final PrinterId generatePrinterId(String localId) {
323269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        throwIfNotCalledOnMainThread();
3244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return new PrinterId(new ComponentName(getPackageName(),
325798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                getClass().getName()), localId);
3264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
328269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    static void throwIfNotCalledOnMainThread() {
329269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (!Looper.getMainLooper().isCurrentThread()) {
330269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throw new IllegalAccessError("must be called from the main thread");
331269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
332269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
333269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
3354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public final IBinder onBind(Intent intent) {
3364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return new IPrintService.Stub() {
3374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
338269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void createPrinterDiscoverySession() {
339269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
340269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
341269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
342269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
343269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void destroyPrinterDiscoverySession() {
344269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
345269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
346269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void startPrinterDiscovery(List<PrinterId> priorityList) {
348269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
349269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        priorityList).sendToTarget();
3504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
353269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void stopPrinterDiscovery() {
354269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_STOP_PRINTER_DISCOVERY);
355269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
356269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
357269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
358d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void validatePrinters(List<PrinterId> printerIds) {
359d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
360d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        printerIds).sendToTarget();
361d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
362d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
363d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            @Override
364d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void startPrinterStateTracking(PrinterId printerId) {
365d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
366d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        printerId).sendToTarget();
367d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
368d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
369d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            @Override
370d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void stopPrinterStateTracking(PrinterId printerId) {
371d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
372269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        printerId).sendToTarget();
373269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
374269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
375269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
376269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void setClient(IPrintServiceClient client) {
377269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.obtainMessage(ServiceHandler.MSG_SET_CLEINT, client)
378269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        .sendToTarget();
3794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
382798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
383798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
384a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        printJobInfo).sendToTarget();
3854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
388a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public void onPrintJobQueued(PrintJobInfo printJobInfo) {
389798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_ON_PRINTJOB_QUEUED,
390a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        printJobInfo).sendToTarget();
3914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        };
3934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
395798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private final class ServiceHandler extends Handler {
396269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
397269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
398269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_START_PRINTER_DISCOVERY = 3;
399269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
400d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_VALIDATE_PRINTERS = 5;
401d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
402d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
403d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_ON_PRINTJOB_QUEUED = 8;
404d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
405d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_SET_CLEINT = 10;
4064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
407798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        public ServiceHandler(Looper looper) {
4084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            super(looper, null, true);
4094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
4104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
412269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        @SuppressWarnings("unchecked")
4134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public void handleMessage(Message message) {
4144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            final int action = message.what;
4154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            switch (action) {
416269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
417b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
418b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_CREATE_PRINTER_DISCOVERY_SESSION "
419b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
420b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
421798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                    PrinterDiscoverySession session = onCreatePrinterDiscoverySession();
422798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                    if (session == null) {
423798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                        throw new NullPointerException("session cannot be null");
4244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
425269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (session.getId() == mLastSessionId) {
426269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        throw new IllegalStateException("cannot reuse session instances");
427269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
428269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mDiscoverySession = session;
429269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mLastSessionId = session.getId();
430269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    session.setObserver(mClient);
431269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
432269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
433269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
434b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
435b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_DESTROY_PRINTER_DISCOVERY_SESSION "
436b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
437b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
438269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
439269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.destroy();
440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession = null;
441269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
442269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
443269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
444269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_START_PRINTER_DISCOVERY: {
445b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
446b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_START_PRINTER_DISCOVERY "
447b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
448b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
449269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
450269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
451269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.startPrinterDiscovery(priorityList);
452269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
453269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
454269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
455269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_STOP_PRINTER_DISCOVERY: {
456b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
457b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_DISCOVERY "
458b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
459b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
460269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
461269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.stopPrinterDiscovery();
462269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
463269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
464269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
465d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_VALIDATE_PRINTERS: {
466b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
467b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_VALIDATE_PRINTERS "
468b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
469b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
470d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (mDiscoverySession != null) {
471d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        List<PrinterId> printerIds = (List<PrinterId>) message.obj;
472d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.validatePrinters(printerIds);
473d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
474d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                } break;
475d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
476d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_START_PRINTER_STATE_TRACKING: {
477b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
478b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_START_PRINTER_STATE_TRACKING "
479b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
480b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
481d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (mDiscoverySession != null) {
482d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        PrinterId printerId = (PrinterId) message.obj;
483d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.startPrinterStateTracking(printerId);
484d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
485d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                } break;
486d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
487d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_STOP_PRINTER_STATE_TRACKING: {
488b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
489b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
490b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
491b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
492269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
493269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        PrinterId printerId = (PrinterId) message.obj;
494d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.stopPrinterStateTracking(printerId);
4954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
4964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
4974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
49855b409a97cf6376399a0940313ea852368727d6fSvetoslav Ganov                case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
499b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
500b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_ON_REQUEST_CANCEL_PRINTJOB "
501b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
502b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
503a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
504a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
5054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
50755b409a97cf6376399a0940313ea852368727d6fSvetoslav Ganov                case MSG_ON_PRINTJOB_QUEUED: {
508b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
509b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_ON_PRINTJOB_QUEUED "
510b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
511b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
512a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
513b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    if (DEBUG) {
514b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                        Log.i(LOG_TAG, "Queued: " + printJobInfo);
515b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    }
516a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onPrintJobQueued(new PrintJob(printJobInfo, mClient));
5174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
51955b409a97cf6376399a0940313ea852368727d6fSvetoslav Ganov                case MSG_SET_CLEINT: {
520b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
521b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_SET_CLEINT "
522b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
523b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
524269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mClient = (IPrintServiceClient) message.obj;
525269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mClient != null) {
5264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        onConnected();
5274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                     } else {
5284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        onDisconnected();
529269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                     }
5304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                default: {
5334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    throw new IllegalArgumentException("Unknown message: " + action);
5344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
5354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
5364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
5374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
539