Home | History | Annotate | Download | only in printservice
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.printservice;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.app.Activity;
     22 import android.app.PendingIntent;
     23 import android.app.Service;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.os.Handler;
     28 import android.os.IBinder;
     29 import android.os.Looper;
     30 import android.os.Message;
     31 import android.os.RemoteException;
     32 import android.print.PrintJobInfo;
     33 import android.print.PrinterId;
     34 import android.print.PrinterInfo;
     35 import android.util.Log;
     36 
     37 import com.android.internal.util.Preconditions;
     38 
     39 import java.util.ArrayList;
     40 import java.util.Collections;
     41 import java.util.List;
     42 
     43 /**
     44  * <p>
     45  * This is the base class for implementing print services. A print service knows
     46  * how to discover and interact one or more printers via one or more protocols.
     47  * </p>
     48  * <h3>Printer discovery</h3>
     49  * <p>
     50  * A print service is responsible for discovering printers, adding discovered printers,
     51  * removing added printers, and updating added printers. When the system is interested
     52  * in printers managed by your service it will call {@link
     53  * #onCreatePrinterDiscoverySession()} from which you must return a new {@link
     54  * PrinterDiscoverySession} instance. The returned session encapsulates the interaction
     55  * between the system and your service during printer discovery. For description of this
     56  * interaction refer to the documentation for {@link PrinterDiscoverySession}.
     57  * </p>
     58  * <p>
     59  * For every printer discovery session all printers have to be added since system does
     60  * not retain printers across sessions. Hence, each printer known to this print service
     61  * should be added only once during a discovery session. Only an already added printer
     62  * can be removed or updated. Removed printers can be added again.
     63  * </p>
     64  * <h3>Print jobs</h3>
     65  * <p>
     66  * When a new print job targeted to a printer managed by this print service is is queued,
     67  * i.e. ready for processing by the print service, you will receive a call to {@link
     68  * #onPrintJobQueued(PrintJob)}. The print service may handle the print job immediately
     69  * or schedule that for an appropriate time in the future. The list of all active print
     70  * jobs for this service is obtained by calling {@link #getActivePrintJobs()}. Active
     71  * print jobs are ones that are queued or started.
     72  * </p>
     73  * <p>
     74  * A print service is responsible for setting a print job's state as appropriate
     75  * while processing it. Initially, a print job is queued, i.e. {@link PrintJob#isQueued()
     76  * PrintJob.isQueued()} returns true, which means that the document to be printed is
     77  * spooled by the system and the print service can begin processing it. You can obtain
     78  * the printed document by calling {@link PrintJob#getDocument() PrintJob.getDocument()}
     79  * whose data is accessed via {@link PrintDocument#getData() PrintDocument.getData()}.
     80  * After the print service starts printing the data it should set the print job's
     81  * state to started by calling {@link PrintJob#start()} after which
     82  * {@link PrintJob#isStarted() PrintJob.isStarted()} would return true. Upon successful
     83  * completion, the print job should be marked as completed by calling {@link
     84  * PrintJob#complete() PrintJob.complete()} after which {@link PrintJob#isCompleted()
     85  * PrintJob.isCompleted()} would return true. In case of a failure, the print job should
     86  * be marked as failed by calling {@link PrintJob#fail(String) PrintJob.fail(
     87  * String)} after which {@link PrintJob#isFailed() PrintJob.isFailed()} would
     88  * return true.
     89  * </p>
     90  * <p>
     91  * If a print job is queued or started and the user requests to cancel it, the print
     92  * service will receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
     93  * requests from the service to do best effort in canceling the job. In case the job
     94  * is successfully canceled, its state has to be marked as cancelled by calling {@link
     95  * PrintJob#cancel() PrintJob.cancel()} after which {@link PrintJob#isCancelled()
     96  * PrintJob.isCacnelled()} would return true.
     97  * </p>
     98  * <h3>Lifecycle</h3>
     99  * <p>
    100  * The lifecycle of a print service is managed exclusively by the system and follows
    101  * the established service lifecycle. Additionally, starting or stopping a print service
    102  * is triggered exclusively by an explicit user action through enabling or disabling it
    103  * in the device settings. After the system binds to a print service, it calls {@link
    104  * #onConnected()}. This method can be overriden by clients to perform post binding setup.
    105  * Also after the system unbinds from a print service, it calls {@link #onDisconnected()}.
    106  * This method can be overriden by clients to perform post unbinding cleanup. Your should
    107  * not do any work after the system disconnected from your print service since the
    108  * service can be killed at any time to reclaim memory. The system will not disconnect
    109  * from a print service if there are active print jobs for the printers managed by it.
    110  * </p>
    111  * <h3>Declaration</h3>
    112  * <p>
    113  * A print service is declared as any other service in an AndroidManifest.xml but it must
    114  * also specify that it handles the {@link android.content.Intent} with action {@link
    115  * #SERVICE_INTERFACE android.printservice.PrintService}. Failure to declare this intent
    116  * will cause the system to ignore the print service. Additionally, a print service must
    117  * request the {@link android.Manifest.permission#BIND_PRINT_SERVICE
    118  * android.permission.BIND_PRINT_SERVICE} permission to ensure that only the system can
    119  * bind to it. Failure to declare this intent will cause the system to ignore the print
    120  * service. Following is an example declaration:
    121  * </p>
    122  * <pre>
    123  * &lt;service android:name=".MyPrintService"
    124  *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
    125  *     &lt;intent-filter&gt;
    126  *         &lt;action android:name="android.printservice.PrintService" /&gt;
    127  *     &lt;/intent-filter&gt;
    128  *     . . .
    129  * &lt;/service&gt;
    130  * </pre>
    131  * <h3>Configuration</h3>
    132  * <p>
    133  * A print service can be configured by specifying an optional settings activity which
    134  * exposes service specific settings, an optional add printers activity which is used for
    135  * manual addition of printers, vendor name ,etc. It is a responsibility of the system
    136  * to launch the settings and add printers activities when appropriate.
    137  * </p>
    138  * <p>
    139  * A print service is configured by providing a {@link #SERVICE_META_DATA meta-data}
    140  * entry in the manifest when declaring the service. A service declaration with a meta-data
    141  * tag is presented below:
    142  * <pre> &lt;service android:name=".MyPrintService"
    143  *         android:permission="android.permission.BIND_PRINT_SERVICE"&gt;
    144  *     &lt;intent-filter&gt;
    145  *         &lt;action android:name="android.printservice.PrintService" /&gt;
    146  *     &lt;/intent-filter&gt;
    147  *     &lt;meta-data android:name="android.printservice" android:resource="@xml/printservice" /&gt;
    148  * &lt;/service&gt;</pre>
    149  * </p>
    150  * <p>
    151  * For more details for how to configure your print service via the meta-data refer to
    152  * {@link #SERVICE_META_DATA} and <code>&lt;{@link android.R.styleable#PrintService
    153  * print-service}&gt;</code>.
    154  * </p>
    155  * <p>
    156  * <strong>Note: </strong> All callbacks in this class are executed on the main
    157  * application thread. You should also invoke any method of this class on the main
    158  * application thread.
    159  * </p>
    160  */
    161 public abstract class PrintService extends Service {
    162 
    163     private static final String LOG_TAG = "PrintService";
    164 
    165     private static final boolean DEBUG = false;
    166 
    167     /**
    168      * The {@link Intent} action that must be declared as handled by a service
    169      * in its manifest for the system to recognize it as a print service.
    170      */
    171     public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
    172 
    173     /**
    174      * Name under which a {@link PrintService} component publishes additional information
    175      * about itself. This meta-data must reference a XML resource containing a <code>
    176      * &lt;{@link android.R.styleable#PrintService print-service}&gt;</code> tag. This is
    177      * a sample XML file configuring a print service:
    178      * <pre> &lt;print-service
    179      *     android:vendor="SomeVendor"
    180      *     android:settingsActivity="foo.bar.MySettingsActivity"
    181      *     andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
    182      *     . . .
    183      * /&gt;</pre>
    184      * <p>
    185      * For detailed configuration options that can be specified via the meta-data
    186      * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
    187      * </p>
    188      * <p>
    189      * If you declare a settings or add a printers activity, they have to be exported,
    190      * by setting the {@link android.R.attr#exported} activity attribute to <code>true
    191      * </code>. Also in case you want only the system to be able to start any of these
    192      * activities you can specify that they request the android.permission
    193      * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
    194      * {@link android.R.attr#permission} activity attribute.
    195      * </p>
    196      */
    197     public static final String SERVICE_META_DATA = "android.printservice";
    198 
    199     /**
    200      * If you declared an optional activity with advanced print options via the
    201      * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity} attribute,
    202      * this extra is used to pass in the currently constructed {@link PrintJobInfo} to your activity
    203      * allowing you to modify it. After you are done, you must return the modified
    204      * {@link PrintJobInfo} via the same extra.
    205      * <p>
    206      * You cannot modify the passed in {@link PrintJobInfo} directly, rather you should build
    207      * another one using the {@link android.print.PrintJobInfo.Builder PrintJobInfo.Builder} class.
    208      * You can specify any standard properties and add advanced, printer specific, ones via
    209      * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, String)
    210      * PrintJobInfo.Builder.putAdvancedOption(String, String)} and
    211      * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, int)
    212      * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options are not
    213      * interpreted by the system, they will not be visible to applications, and can only be accessed
    214      * by your print service via {@link PrintJob#getAdvancedStringOption(String)
    215      * PrintJob.getAdvancedStringOption(String)} and {@link PrintJob#getAdvancedIntOption(String)
    216      * PrintJob.getAdvancedIntOption(String)}.
    217      * </p>
    218      * <p>
    219      * If the advanced print options activity offers changes to the standard print options, you can
    220      * get the current {@link android.print.PrinterInfo PrinterInfo} using the
    221      * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user with UI options
    222      * supported by the current printer. For example, if the current printer does not support a
    223      * given media size, you should not offer it in the advanced print options UI.
    224      * </p>
    225      *
    226      * @see #EXTRA_PRINTER_INFO
    227      */
    228     public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
    229 
    230     /**
    231      * If you declared an optional activity with advanced print options via the
    232      * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
    233      * attribute, this extra is used to pass in the currently selected printer's
    234      * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
    235      *
    236      * @see #EXTRA_PRINT_JOB_INFO
    237      */
    238     public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
    239 
    240     /**
    241      * If you declared an optional activity with advanced print options via the
    242      * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
    243      * attribute, this extra is used to pass in the meta-data for the currently printed
    244      * document as a {@link android.print.PrintDocumentInfo} to your activity allowing
    245      * you to inspect it.
    246      *
    247      * @see #EXTRA_PRINT_JOB_INFO
    248      * @see #EXTRA_PRINTER_INFO
    249      */
    250     public static final String EXTRA_PRINT_DOCUMENT_INFO =
    251             "android.printservice.extra.PRINT_DOCUMENT_INFO";
    252 
    253     /**
    254      * When the {@link PendingIntent} declared via
    255      * {@link PrinterInfo.Builder#setInfoIntent(PendingIntent)} is called this boolean extra
    256      * will be filled in if the activity can select the printer.
    257      *
    258      * @see #EXTRA_SELECT_PRINTER
    259      */
    260     public static final String EXTRA_CAN_SELECT_PRINTER =
    261             "android.printservice.extra.CAN_SELECT_PRINTER";
    262 
    263     /**
    264      * If this boolean extra is set to {@code true} in the {@link Activity#setResult(int, Intent)
    265      * result data} from the activity specified in
    266      * {@link PrinterInfo.Builder#setInfoIntent(PendingIntent)} the printer will be selected.
    267      *
    268      * @see #EXTRA_CAN_SELECT_PRINTER
    269      */
    270     public static final String EXTRA_SELECT_PRINTER =
    271             "android.printservice.extra.SELECT_PRINTER";
    272 
    273     private Handler mHandler;
    274 
    275     private IPrintServiceClient mClient;
    276 
    277     private int mLastSessionId = -1;
    278 
    279     private PrinterDiscoverySession mDiscoverySession;
    280 
    281     @Override
    282     protected final void attachBaseContext(Context base) {
    283         super.attachBaseContext(base);
    284         mHandler = new ServiceHandler(base.getMainLooper());
    285     }
    286 
    287     /**
    288      * The system has connected to this service.
    289      */
    290     protected void onConnected() {
    291         /* do nothing */
    292     }
    293 
    294     /**
    295      * The system has disconnected from this service.
    296      */
    297     protected void onDisconnected() {
    298         /* do nothing */
    299     }
    300 
    301     /**
    302      * Callback asking you to create a new {@link PrinterDiscoverySession}.
    303      *
    304      * @return The created session.
    305      * @see PrinterDiscoverySession
    306      */
    307     protected abstract @Nullable PrinterDiscoverySession onCreatePrinterDiscoverySession();
    308 
    309     /**
    310      * Called when cancellation of a print job is requested. The service
    311      * should do best effort to fulfill the request. After the cancellation
    312      * is performed, the print job should be marked as cancelled state by
    313      * calling {@link PrintJob#cancel()}.
    314      *
    315      * @param printJob The print job to cancel.
    316      *
    317      * @see PrintJob#cancel() PrintJob.cancel()
    318      * @see PrintJob#isCancelled() PrintJob.isCancelled()
    319      */
    320     protected abstract void onRequestCancelPrintJob(PrintJob printJob);
    321 
    322     /**
    323      * Called when there is a queued print job for one of the printers
    324      * managed by this print service.
    325      *
    326      * @param printJob The new queued print job.
    327      *
    328      * @see PrintJob#isQueued() PrintJob.isQueued()
    329      * @see #getActivePrintJobs()
    330      */
    331     protected abstract void onPrintJobQueued(PrintJob printJob);
    332 
    333     /**
    334      * Gets the active print jobs for the printers managed by this service.
    335      * Active print jobs are ones that are not in a final state, i.e. whose
    336      * state is queued or started.
    337      *
    338      * @return The active print jobs.
    339      *
    340      * @see PrintJob#isQueued() PrintJob.isQueued()
    341      * @see PrintJob#isStarted() PrintJob.isStarted()
    342      */
    343     public final List<PrintJob> getActivePrintJobs() {
    344         throwIfNotCalledOnMainThread();
    345         if (mClient == null) {
    346             return Collections.emptyList();
    347         }
    348         try {
    349             List<PrintJob> printJobs = null;
    350             List<PrintJobInfo> printJobInfos = mClient.getPrintJobInfos();
    351             if (printJobInfos != null) {
    352                 final int printJobInfoCount = printJobInfos.size();
    353                 printJobs = new ArrayList<PrintJob>(printJobInfoCount);
    354                 for (int i = 0; i < printJobInfoCount; i++) {
    355                     printJobs.add(new PrintJob(this, printJobInfos.get(i), mClient));
    356                 }
    357             }
    358             if (printJobs != null) {
    359                 return printJobs;
    360             }
    361         } catch (RemoteException re) {
    362             Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
    363         }
    364         return Collections.emptyList();
    365     }
    366 
    367     /**
    368      * Generates a global printer id given the printer's locally unique one.
    369      *
    370      * @param localId A locally unique id in the context of your print service.
    371      * @return Global printer id.
    372      */
    373     public @NonNull final PrinterId generatePrinterId(String localId) {
    374         throwIfNotCalledOnMainThread();
    375         localId = Preconditions.checkNotNull(localId, "localId cannot be null");
    376         return new PrinterId(new ComponentName(getPackageName(),
    377                 getClass().getName()), localId);
    378     }
    379 
    380     static void throwIfNotCalledOnMainThread() {
    381         if (!Looper.getMainLooper().isCurrentThread()) {
    382             throw new IllegalAccessError("must be called from the main thread");
    383         }
    384     }
    385 
    386     @Override
    387     public final IBinder onBind(Intent intent) {
    388         return new IPrintService.Stub() {
    389             @Override
    390             public void createPrinterDiscoverySession() {
    391                 mHandler.sendEmptyMessage(ServiceHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
    392             }
    393 
    394             @Override
    395             public void destroyPrinterDiscoverySession() {
    396                 mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
    397             }
    398 
    399             @Override
    400             public void startPrinterDiscovery(List<PrinterId> priorityList) {
    401                 mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
    402                         priorityList).sendToTarget();
    403             }
    404 
    405             @Override
    406             public void stopPrinterDiscovery() {
    407                 mHandler.sendEmptyMessage(ServiceHandler.MSG_STOP_PRINTER_DISCOVERY);
    408             }
    409 
    410             @Override
    411             public void validatePrinters(List<PrinterId> printerIds) {
    412                 mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
    413                         printerIds).sendToTarget();
    414             }
    415 
    416             @Override
    417             public void startPrinterStateTracking(PrinterId printerId) {
    418                 mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
    419                         printerId).sendToTarget();
    420             }
    421 
    422             @Override
    423             public void requestCustomPrinterIcon(PrinterId printerId) {
    424                 mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_CUSTOM_PRINTER_ICON,
    425                         printerId).sendToTarget();
    426             }
    427 
    428             @Override
    429             public void stopPrinterStateTracking(PrinterId printerId) {
    430                 mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
    431                         printerId).sendToTarget();
    432             }
    433 
    434             @Override
    435             public void setClient(IPrintServiceClient client) {
    436                 mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client)
    437                         .sendToTarget();
    438             }
    439 
    440             @Override
    441             public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
    442                 mHandler.obtainMessage(ServiceHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
    443                         printJobInfo).sendToTarget();
    444             }
    445 
    446             @Override
    447             public void onPrintJobQueued(PrintJobInfo printJobInfo) {
    448                 mHandler.obtainMessage(ServiceHandler.MSG_ON_PRINTJOB_QUEUED,
    449                         printJobInfo).sendToTarget();
    450             }
    451         };
    452     }
    453 
    454     private final class ServiceHandler extends Handler {
    455         public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
    456         public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
    457         public static final int MSG_START_PRINTER_DISCOVERY = 3;
    458         public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
    459         public static final int MSG_VALIDATE_PRINTERS = 5;
    460         public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
    461         public static final int MSG_REQUEST_CUSTOM_PRINTER_ICON = 7;
    462         public static final int MSG_STOP_PRINTER_STATE_TRACKING = 8;
    463         public static final int MSG_ON_PRINTJOB_QUEUED = 9;
    464         public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 10;
    465         public static final int MSG_SET_CLIENT = 11;
    466 
    467         public ServiceHandler(Looper looper) {
    468             super(looper, null, true);
    469         }
    470 
    471         @Override
    472         @SuppressWarnings("unchecked")
    473         public void handleMessage(Message message) {
    474             final int action = message.what;
    475             switch (action) {
    476                 case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
    477                     if (DEBUG) {
    478                         Log.i(LOG_TAG, "MSG_CREATE_PRINTER_DISCOVERY_SESSION "
    479                                 + getPackageName());
    480                     }
    481                     PrinterDiscoverySession session = onCreatePrinterDiscoverySession();
    482                     if (session == null) {
    483                         throw new NullPointerException("session cannot be null");
    484                     }
    485                     if (session.getId() == mLastSessionId) {
    486                         throw new IllegalStateException("cannot reuse session instances");
    487                     }
    488                     mDiscoverySession = session;
    489                     mLastSessionId = session.getId();
    490                     session.setObserver(mClient);
    491                 } break;
    492 
    493                 case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
    494                     if (DEBUG) {
    495                         Log.i(LOG_TAG, "MSG_DESTROY_PRINTER_DISCOVERY_SESSION "
    496                                 + getPackageName());
    497                     }
    498                     if (mDiscoverySession != null) {
    499                         mDiscoverySession.destroy();
    500                         mDiscoverySession = null;
    501                     }
    502                 } break;
    503 
    504                 case MSG_START_PRINTER_DISCOVERY: {
    505                     if (DEBUG) {
    506                         Log.i(LOG_TAG, "MSG_START_PRINTER_DISCOVERY "
    507                                 + getPackageName());
    508                     }
    509                     if (mDiscoverySession != null) {
    510                         List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
    511                         mDiscoverySession.startPrinterDiscovery(priorityList);
    512                     }
    513                 } break;
    514 
    515                 case MSG_STOP_PRINTER_DISCOVERY: {
    516                     if (DEBUG) {
    517                         Log.i(LOG_TAG, "MSG_STOP_PRINTER_DISCOVERY "
    518                                 + getPackageName());
    519                     }
    520                     if (mDiscoverySession != null) {
    521                         mDiscoverySession.stopPrinterDiscovery();
    522                     }
    523                 } break;
    524 
    525                 case MSG_VALIDATE_PRINTERS: {
    526                     if (DEBUG) {
    527                         Log.i(LOG_TAG, "MSG_VALIDATE_PRINTERS "
    528                                 + getPackageName());
    529                     }
    530                     if (mDiscoverySession != null) {
    531                         List<PrinterId> printerIds = (List<PrinterId>) message.obj;
    532                         mDiscoverySession.validatePrinters(printerIds);
    533                     }
    534                 } break;
    535 
    536                 case MSG_START_PRINTER_STATE_TRACKING: {
    537                     if (DEBUG) {
    538                         Log.i(LOG_TAG, "MSG_START_PRINTER_STATE_TRACKING "
    539                                 + getPackageName());
    540                     }
    541                     if (mDiscoverySession != null) {
    542                         PrinterId printerId = (PrinterId) message.obj;
    543                         mDiscoverySession.startPrinterStateTracking(printerId);
    544                     }
    545                 } break;
    546 
    547                 case MSG_REQUEST_CUSTOM_PRINTER_ICON: {
    548                     if (DEBUG) {
    549                         Log.i(LOG_TAG, "MSG_REQUEST_CUSTOM_PRINTER_ICON "
    550                                 + getPackageName());
    551                     }
    552                     if (mDiscoverySession != null) {
    553                         PrinterId printerId = (PrinterId) message.obj;
    554                         mDiscoverySession.requestCustomPrinterIcon(printerId);
    555                     }
    556                 } break;
    557 
    558                 case MSG_STOP_PRINTER_STATE_TRACKING: {
    559                     if (DEBUG) {
    560                         Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
    561                                 + getPackageName());
    562                     }
    563                     if (mDiscoverySession != null) {
    564                         PrinterId printerId = (PrinterId) message.obj;
    565                         mDiscoverySession.stopPrinterStateTracking(printerId);
    566                     }
    567                 } break;
    568 
    569                 case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
    570                     if (DEBUG) {
    571                         Log.i(LOG_TAG, "MSG_ON_REQUEST_CANCEL_PRINTJOB "
    572                                 + getPackageName());
    573                     }
    574                     PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
    575                     onRequestCancelPrintJob(new PrintJob(PrintService.this, printJobInfo, mClient));
    576                 } break;
    577 
    578                 case MSG_ON_PRINTJOB_QUEUED: {
    579                     if (DEBUG) {
    580                         Log.i(LOG_TAG, "MSG_ON_PRINTJOB_QUEUED "
    581                                 + getPackageName());
    582                     }
    583                     PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
    584                     if (DEBUG) {
    585                         Log.i(LOG_TAG, "Queued: " + printJobInfo);
    586                     }
    587                     onPrintJobQueued(new PrintJob(PrintService.this, printJobInfo, mClient));
    588                 } break;
    589 
    590                 case MSG_SET_CLIENT: {
    591                     if (DEBUG) {
    592                         Log.i(LOG_TAG, "MSG_SET_CLIENT "
    593                                 + getPackageName());
    594                     }
    595                     mClient = (IPrintServiceClient) message.obj;
    596                     if (mClient != null) {
    597                         onConnected();
    598                      } else {
    599                         onDisconnected();
    600                      }
    601                 } break;
    602 
    603                 default: {
    604                     throw new IllegalArgumentException("Unknown message: " + action);
    605                 }
    606             }
    607         }
    608     }
    609 }
    610