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
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Service;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName;
214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Context;
224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Handler;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.IBinder;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Looper;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo;
294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrinterId;
304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.ArrayList;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Collections;
344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.List;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
38798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * This is the base class for implementing print services. A print service knows
39798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * how to discover and interact one or more printers via one or more protocols.
404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Printer discovery</h3>
424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
43798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is responsible for discovering printers, adding discovered printers,
44798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * removing added printers, and updating added printers. When the system is interested
45798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * in printers managed by your service it will call {@link
46798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onCreatePrinterDiscoverySession()} from which you must return a new {@link
47798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrinterDiscoverySession} instance. The returned session encapsulates the interaction
48798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * between the system and your service during printer discovery. For description of this
49798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * interaction refer to the documentation for {@link PrinterDiscoverySession}.
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
52798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * For every printer discovery session all printers have to be added since system does
53798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * not retain printers across sessions. Hence, each printer known to this print service
54798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * should be added only once during a discovery session. Only an already added printer
55798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * can be removed or updated. Removed printers can be added again.
564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Print jobs</h3>
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
59798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * When a new print job targeted to a printer managed by this print service is is queued,
60798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * i.e. ready for processing by the print service, you will receive a call to {@link
61798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onPrintJobQueued(PrintJob)}. The print service may handle the print job immediately
62798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * or schedule that for an appropriate time in the future. The list of all active print
63798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * jobs for this service is obtained by calling {@link #getActivePrintJobs()}. Active
64798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * print jobs are ones that are queued or started.
654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
67798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is responsible for setting a print job's state as appropriate
68798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * while processing it. Initially, a print job is queued, i.e. {@link PrintJob#isQueued()
69798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isQueued()} returns true, which means that the document to be printed is
70798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * spooled by the system and the print service can begin processing it. You can obtain
71798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * the printed document by calling {@link PrintJob#getDocument() PrintJob.getDocument()}
72798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * whose data is accessed via {@link PrintDocument#getData() PrintDocument.getData()}.
73798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * After the print service starts printing the data it should set the print job's
74798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * state to started by calling {@link PrintJob#start()} after which
75798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * {@link PrintJob#isStarted() PrintJob.isStarted()} would return true. Upon successful
76798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * completion, the print job should be marked as completed by calling {@link
77798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob#complete() PrintJob.complete()} after which {@link PrintJob#isCompleted()
78798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isCompleted()} would return true. In case of a failure, the print job should
793bf7976e78d69310b67f4f19f49b2eb839252b67Svetoslav Ganov * be marked as failed by calling {@link PrintJob#fail(String) PrintJob.fail(
803bf7976e78d69310b67f4f19f49b2eb839252b67Svetoslav Ganov * String)} after which {@link PrintJob#isFailed() PrintJob.isFailed()} would
81798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * return true.
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * </p>
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov * <p>
84798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * If a print job is queued or started and the user requests to cancel it, the print
85798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service will receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
86798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * requests from the service to do best effort in canceling the job. In case the job
87798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * is successfully canceled, its state has to be marked as cancelled by calling {@link
88798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob#cancel() PrintJob.cancel()} after which {@link PrintJob#isCancelled()
89798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * PrintJob.isCacnelled()} would return true.
904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Lifecycle</h3>
924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
93798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * The lifecycle of a print service is managed exclusively by the system and follows
94798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * the established service lifecycle. Additionally, starting or stopping a print service
95798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * is triggered exclusively by an explicit user action through enabling or disabling it
96798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * in the device settings. After the system binds to a print service, it calls {@link
97798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #onConnected()}. This method can be overriden by clients to perform post binding setup.
98798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * Also after the system unbinds from a print service, it calls {@link #onDisconnected()}.
99798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * This method can be overriden by clients to perform post unbinding cleanup. Your should
100798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * not do any work after the system disconnected from your print service since the
101798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service can be killed at any time to reclaim memory. The system will not disconnect
102798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * from a print service if there are active print jobs for the printers managed by it.
1034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Declaration</h3>
1054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
106798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is declared as any other service in an AndroidManifest.xml but it must
107798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * also specify that it handles the {@link android.content.Intent} with action {@link
108798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * #SERVICE_INTERFACE android.printservice.PrintService}. Failure to declare this intent
109798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * will cause the system to ignore the print service. Additionally, a print service must
110798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * request the {@link android.Manifest.permission#BIND_PRINT_SERVICE
111798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * android.permission.BIND_PRINT_SERVICE} permission to ensure that only the system can
112798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * bind to it. Failure to declare this intent will cause the system to ignore the print
113798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * service. Following is an example declaration:
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <pre>
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;service android:name=".MyPrintService"
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
1184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;intent-filter&gt;
1194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         &lt;action android:name="android.printservice.PrintService" /&gt;
1204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;/intent-filter&gt;
1214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     . . .
1224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;/service&gt;
1234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </pre>
1244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <h3>Configuration</h3>
1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
126798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service can be configured by specifying an optional settings activity which
127798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * exposes service specific settings, an optional add printers activity which is used for
128798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * manual addition of printers, vendor name ,etc. It is a responsibility of the system
129798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * to launch the settings and add printers activities when appropriate.
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
132798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * A print service is configured by providing a {@link #SERVICE_META_DATA meta-data}
133798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * entry in the manifest when declaring the service. A service declaration with a meta-data
134798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * tag is presented below:
1354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <pre> &lt;service android:name=".MyPrintService"
1364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
1374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;intent-filter&gt;
1384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         &lt;action android:name="android.printservice.PrintService" /&gt;
1394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;/intent-filter&gt;
1404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *     &lt;meta-data android:name="android.printservice" android:resource="@xml/printservice" /&gt;
1414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * &lt;/service&gt;</pre>
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
144798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * For more details for how to configure your print service via the meta-data refer to
145798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * {@link #SERVICE_META_DATA} and <code>&lt;{@link android.R.styleable#PrintService
146798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * print-service}&gt;</code>.
1474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
148269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * <p>
149269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * <strong>Note: </strong> All callbacks in this class are executed on the main
150269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * application thread. You should also invoke any method of this class on the main
151269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * application thread.
152269403b032f965ff3847eb982c2f697229dc5a92Svetoslav * </p>
1534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic abstract class PrintService extends Service {
1554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final String LOG_TAG = "PrintService";
1574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
158b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    private static final boolean DEBUG = false;
159b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
1604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
1614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The {@link Intent} action that must be declared as handled by a service
162798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * in its manifest for the system to recognize it as a print service.
1634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
1654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
167798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Name under which a {@link PrintService} component publishes additional information
168798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * about itself. This meta-data must reference a XML resource containing a <code>
169798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * &lt;{@link android.R.styleable#PrintService print-service}&gt;</code> tag. This is
170798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * a sample XML file configuring a print service:
1714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * <pre> &lt;print-service
172a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     *     android:vendor="SomeVendor"
1734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     android:settingsActivity="foo.bar.MySettingsActivity"
1744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
1754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *     . . .
1764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * /&gt;</pre>
177798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * <p>
178798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * For detailed configuration options that can be specified via the meta-data
179798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
180798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * </p>
181860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * <p>
182860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * If you declare a settings or add a printers activity, they have to be exported,
183860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * by setting the {@link android.R.attr#exported} activity attribute to <code>true
184860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * </code>. Also in case you want only the system to be able to start any of these
185860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * activities you can specify that they request the android.permission
186860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
187860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * {@link android.R.attr#permission} activity attribute.
188860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * </p>
1894b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String SERVICE_META_DATA = "android.printservice";
1914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1921c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav    /**
1931c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * If you declared an optional activity with advanced print options via the
1940d9ada9fdd1a609ded3fed4328021a5fe26d898dNarayan Kamath     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
1951c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * attribute, this extra is used to pass in the currently constructed {@link
1961c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo} to your activity allowing you to modify it. After you are
1971c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * done, you must return the modified {@link PrintJobInfo} via the same extra.
1981c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * <p>
1991c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
2001c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * should build another one using the {@link PrintJobInfo.Builder} class. You
2011c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * can specify any standard properties and add advanced, printer specific,
2021c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
203a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
2041c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJobInfo.Builder#putAdvancedOption(String, int)
205a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
2061c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * are not interpreted by the system, they will not be visible to applications,
2071c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * and can only be accessed by your print service via {@link
2081c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
2091c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
2101c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     * </p>
211b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * <p>
212b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * If the advanced print options activity offers changes to the standard print
213b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * options, you can get the current {@link android.print.PrinterInfo} using the
214a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
215a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * with UI options supported by the current printer. For example, if the current
216a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * printer does not support a given media size, you should not offer it in the
217a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * advanced print options UI.
218b4fda134761c9521a7e127db3806a07a18763b77Svetoslav     * </p>
219a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     *
220a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * @see #EXTRA_PRINTER_INFO
2211c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav     */
2221c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav    public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
2231c43fceaaa5f9aa6e29e2670f44f312632241007Svetoslav
224a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav    /**
225a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * If you declared an optional activity with advanced print options via the
2260d9ada9fdd1a609ded3fed4328021a5fe26d898dNarayan Kamath     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
227a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * attribute, this extra is used to pass in the currently selected printer's
228a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
229a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     *
230a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     * @see #EXTRA_PRINT_JOB_INFO
231a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav     */
2328fbd0dc30328338cb7a6675ce7e0fe48a7815e1bSvet Ganov    public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
233a798c0a984f29f7180883a61839f68d2cbf0c6ceSvetoslav
2345772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov    /**
2355772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * If you declared an optional activity with advanced print options via the
2365772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
2375772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * attribute, this extra is used to pass in the meta-data for the currently printed
2385772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * document as a {@link android.print.PrintDocumentInfo} to your activity allowing
2395772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * you to inspect it.
2405772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     *
2415772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * @see #EXTRA_PRINT_JOB_INFO
2425772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     * @see #EXTRA_PRINTER_INFO
2435772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov     */
2445772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov    public static final String EXTRA_PRINT_DOCUMENT_INFO =
2455772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov            "android.printservice.extra.PRINT_DOCUMENT_INFO";
2465772b5c671a13d9c4bbc1e3803667166f811cb33Svet Ganov
2474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private Handler mHandler;
2484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private IPrintServiceClient mClient;
2504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
251798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private int mLastSessionId = -1;
2524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
253269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    private PrinterDiscoverySession mDiscoverySession;
254269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
2554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
256798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected final void attachBaseContext(Context base) {
2574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        super.attachBaseContext(base);
258798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        mHandler = new ServiceHandler(base.getMainLooper());
2594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The system has connected to this service.
2634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
2644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected void onConnected() {
2654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        /* do nothing */
2664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * The system has disconnected from this service.
2704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
2714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected void onDisconnected() {
2724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        /* do nothing */
2734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
276798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Callback asking you to create a new {@link PrinterDiscoverySession}.
2774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
278798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrinterDiscoverySession
2794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
280798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
2814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
283798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Called when cancellation of a print job is requested. The service
284a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * should do best effort to fulfill the request. After the cancellation
285798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * is performed, the print job should be marked as cancelled state by
286a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * calling {@link PrintJob#cancel()}.
2874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
288798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param printJob The print job to cancel.
289798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
290798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#cancel() PrintJob.cancel()
291798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isCancelled() PrintJob.isCancelled()
2924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
293798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    protected abstract void onRequestCancelPrintJob(PrintJob printJob);
2944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
2964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Called when there is a queued print job for one of the printers
297798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * managed by this print service.
2984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
2994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param printJob The new queued print job.
3004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
301798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isQueued() PrintJob.isQueued()
302798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see #getActivePrintJobs()
3034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
3044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    protected abstract void onPrintJobQueued(PrintJob printJob);
3054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
307798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Gets the active print jobs for the printers managed by this service.
308798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Active print jobs are ones that are not in a final state, i.e. whose
309798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * state is queued or started.
3104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
311798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @return The active print jobs.
312798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
313798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isQueued() PrintJob.isQueued()
314798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @see PrintJob#isStarted() PrintJob.isStarted()
3154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
316798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public final List<PrintJob> getActivePrintJobs() {
317269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        throwIfNotCalledOnMainThread();
318269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (mClient == null) {
319a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return Collections.emptyList();
320a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
321a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        try {
322a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            List<PrintJob> printJobs = null;
323269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            List<PrintJobInfo> printJobInfos = mClient.getPrintJobInfos();
324a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (printJobInfos != null) {
325a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                final int printJobInfoCount = printJobInfos.size();
326a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                printJobs = new ArrayList<PrintJob>(printJobInfoCount);
327a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                for (int i = 0; i < printJobInfoCount; i++) {
328269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
3294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
3304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
331a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (printJobs != null) {
332a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return printJobs;
333a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
334a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        } catch (RemoteException re) {
335a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
3364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
337a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return Collections.emptyList();
3384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
341798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Generates a global printer id given the printer's locally unique one.
3424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
343798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param localId A locally unique id in the context of your print service.
3444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @return Global printer id.
3454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
346798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public final PrinterId generatePrinterId(String localId) {
347269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        throwIfNotCalledOnMainThread();
3484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return new PrinterId(new ComponentName(getPackageName(),
349798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                getClass().getName()), localId);
3504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
352269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    static void throwIfNotCalledOnMainThread() {
353269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        if (!Looper.getMainLooper().isCurrentThread()) {
354269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            throw new IllegalAccessError("must be called from the main thread");
355269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        }
356269403b032f965ff3847eb982c2f697229dc5a92Svetoslav    }
357269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
3584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
3594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public final IBinder onBind(Intent intent) {
3604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return new IPrintService.Stub() {
3614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
362269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void createPrinterDiscoverySession() {
363269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
364269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
365269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
366269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
367269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void destroyPrinterDiscoverySession() {
368269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
369269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
370269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
371269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void startPrinterDiscovery(List<PrinterId> priorityList) {
372269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
373269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        priorityList).sendToTarget();
3744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
377269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void stopPrinterDiscovery() {
378269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                mHandler.sendEmptyMessage(ServiceHandler.MSG_STOP_PRINTER_DISCOVERY);
379269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
380269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
381269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
382d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void validatePrinters(List<PrinterId> printerIds) {
383d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
384d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        printerIds).sendToTarget();
385d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
386d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
387d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            @Override
388d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void startPrinterStateTracking(PrinterId printerId) {
389d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
390d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        printerId).sendToTarget();
391d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            }
392d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
393d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            @Override
394d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            public void stopPrinterStateTracking(PrinterId printerId) {
395d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
396269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        printerId).sendToTarget();
397269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            }
398269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
399269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            @Override
400269403b032f965ff3847eb982c2f697229dc5a92Svetoslav            public void setClient(IPrintServiceClient client) {
401eae626fd8c9ecb91c43ccb1dda050de52f9795c0jangwon.lee                mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client)
402269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        .sendToTarget();
4034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
406798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
407798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
408a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        printJobInfo).sendToTarget();
4094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
412a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public void onPrintJobQueued(PrintJobInfo printJobInfo) {
413798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                mHandler.obtainMessage(ServiceHandler.MSG_ON_PRINTJOB_QUEUED,
414a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        printJobInfo).sendToTarget();
4154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        };
4174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
4184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
419798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private final class ServiceHandler extends Handler {
420269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
421269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
422269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_START_PRINTER_DISCOVERY = 3;
423269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
424d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_VALIDATE_PRINTERS = 5;
425d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
426d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
427d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_ON_PRINTJOB_QUEUED = 8;
428d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
429eae626fd8c9ecb91c43ccb1dda050de52f9795c0jangwon.lee        public static final int MSG_SET_CLIENT = 10;
4304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
431798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        public ServiceHandler(Looper looper) {
4324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            super(looper, null, true);
4334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
4344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
436269403b032f965ff3847eb982c2f697229dc5a92Svetoslav        @SuppressWarnings("unchecked")
4374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public void handleMessage(Message message) {
4384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            final int action = message.what;
4394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            switch (action) {
440269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
441b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
442b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_CREATE_PRINTER_DISCOVERY_SESSION "
443b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
444b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
445798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                    PrinterDiscoverySession session = onCreatePrinterDiscoverySession();
446798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                    if (session == null) {
447798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                        throw new NullPointerException("session cannot be null");
4484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
449269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (session.getId() == mLastSessionId) {
450269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        throw new IllegalStateException("cannot reuse session instances");
451269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
452269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mDiscoverySession = session;
453269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mLastSessionId = session.getId();
454269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    session.setObserver(mClient);
455269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
456269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
457269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
458b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
459b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_DESTROY_PRINTER_DISCOVERY_SESSION "
460b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
461b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
462269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
463269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.destroy();
464269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession = null;
465269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
466269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
467269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
468269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_START_PRINTER_DISCOVERY: {
469b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
470b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_START_PRINTER_DISCOVERY "
471b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
472b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
473269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
474269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
475269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.startPrinterDiscovery(priorityList);
476269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
477269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
478269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
479269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                case MSG_STOP_PRINTER_DISCOVERY: {
480b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
481b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_DISCOVERY "
482b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
483b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
484269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
485269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        mDiscoverySession.stopPrinterDiscovery();
486269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    }
487269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                } break;
488269403b032f965ff3847eb982c2f697229dc5a92Svetoslav
489d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_VALIDATE_PRINTERS: {
490b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
491b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_VALIDATE_PRINTERS "
492b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
493b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
494d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (mDiscoverySession != null) {
495d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        List<PrinterId> printerIds = (List<PrinterId>) message.obj;
496d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.validatePrinters(printerIds);
497d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
498d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                } break;
499d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
500d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_START_PRINTER_STATE_TRACKING: {
501b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
502b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_START_PRINTER_STATE_TRACKING "
503b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
504b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
505d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    if (mDiscoverySession != null) {
506d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        PrinterId printerId = (PrinterId) message.obj;
507d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.startPrinterStateTracking(printerId);
508d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    }
509d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                } break;
510d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
511d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                case MSG_STOP_PRINTER_STATE_TRACKING: {
512b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
513b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
514b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
515b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
516269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mDiscoverySession != null) {
517269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                        PrinterId printerId = (PrinterId) message.obj;
518d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        mDiscoverySession.stopPrinterStateTracking(printerId);
5194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
5204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
52255b409a97cf6376399a0940313ea852368727d6fSvetoslav Ganov                case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
523b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
524b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_ON_REQUEST_CANCEL_PRINTJOB "
525b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
526b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
527a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
528a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
5294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
53155b409a97cf6376399a0940313ea852368727d6fSvetoslav Ganov                case MSG_ON_PRINTJOB_QUEUED: {
532b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
533b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                        Log.i(LOG_TAG, "MSG_ON_PRINTJOB_QUEUED "
534b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
535b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
536a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
537b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    if (DEBUG) {
538b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                        Log.i(LOG_TAG, "Queued: " + printJobInfo);
539b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    }
540a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    onPrintJobQueued(new PrintJob(printJobInfo, mClient));
5414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
543eae626fd8c9ecb91c43ccb1dda050de52f9795c0jangwon.lee                case MSG_SET_CLIENT: {
544b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    if (DEBUG) {
545eae626fd8c9ecb91c43ccb1dda050de52f9795c0jangwon.lee                        Log.i(LOG_TAG, "MSG_SET_CLIENT "
546b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                                + getPackageName());
547b5f180608db6de123b54ae94de569ff1ebca705cSvetoslav                    }
548269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    mClient = (IPrintServiceClient) message.obj;
549269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                    if (mClient != null) {
5504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        onConnected();
5514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                     } else {
5524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        onDisconnected();
553269403b032f965ff3847eb982c2f697229dc5a92Svetoslav                     }
5544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } break;
5554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                default: {
5574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    throw new IllegalArgumentException("Unknown message: " + action);
5584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
5594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
5604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
5614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
563