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.os.RemoteException;
     20 import android.print.PrintJobId;
     21 import android.print.PrintJobInfo;
     22 import android.text.TextUtils;
     23 import android.util.Log;
     24 
     25 /**
     26  * This class represents a print job from the perspective of a print
     27  * service. It provides APIs for observing the print job state and
     28  * performing operations on the print job.
     29  * <p>
     30  * <strong>Note: </strong> All methods of this class must be invoked on
     31  * the main application thread.
     32  * </p>
     33  */
     34 public final class PrintJob {
     35 
     36     private static final String LOG_TAG = "PrintJob";
     37 
     38     private final IPrintServiceClient mPrintServiceClient;
     39 
     40     private final PrintDocument mDocument;
     41 
     42     private PrintJobInfo mCachedInfo;
     43 
     44     PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
     45         mCachedInfo = jobInfo;
     46         mPrintServiceClient = client;
     47         mDocument = new PrintDocument(mCachedInfo.getId(), client,
     48                 jobInfo.getDocumentInfo());
     49     }
     50 
     51     /**
     52      * Gets the unique print job id.
     53      *
     54      * @return The id.
     55      */
     56     public PrintJobId getId() {
     57         PrintService.throwIfNotCalledOnMainThread();
     58         return mCachedInfo.getId();
     59     }
     60 
     61     /**
     62      * Gets the {@link PrintJobInfo} that describes this job.
     63      * <p>
     64      * <strong>Node:</strong>The returned info object is a snapshot of the
     65      * current print job state. Every call to this method returns a fresh
     66      * info object that reflects the current print job state.
     67      * </p>
     68      *
     69      * @return The print job info.
     70      */
     71     public PrintJobInfo getInfo() {
     72         PrintService.throwIfNotCalledOnMainThread();
     73         if (isInImmutableState()) {
     74             return mCachedInfo;
     75         }
     76         PrintJobInfo info = null;
     77         try {
     78             info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
     79         } catch (RemoteException re) {
     80             Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re);
     81         }
     82         if (info != null) {
     83             mCachedInfo = info;
     84         }
     85         return mCachedInfo;
     86     }
     87 
     88     /**
     89      * Gets the printed document.
     90      *
     91      * @return The document.
     92      */
     93     public PrintDocument getDocument() {
     94         PrintService.throwIfNotCalledOnMainThread();
     95         return mDocument;
     96     }
     97 
     98     /**
     99      * Gets whether this print job is queued. Such a print job is
    100      * ready to be printed and can be started or cancelled.
    101      *
    102      * @return Whether the print job is queued.
    103      *
    104      * @see #start()
    105      * @see #cancel()
    106      */
    107     public boolean isQueued() {
    108         PrintService.throwIfNotCalledOnMainThread();
    109         return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
    110     }
    111 
    112     /**
    113      * Gets whether this print job is started. Such a print job is
    114      * being printed and can be completed or canceled or failed.
    115      *
    116      * @return Whether the print job is started.
    117      *
    118      * @see #complete()
    119      * @see #cancel()
    120      * @see #fail(CharSequence)
    121      */
    122     public boolean isStarted() {
    123         PrintService.throwIfNotCalledOnMainThread();
    124         return getInfo().getState() == PrintJobInfo.STATE_STARTED;
    125     }
    126 
    127     /**
    128      * Gets whether this print job is blocked. Such a print job is halted
    129      * due to an abnormal condition and can be started or canceled or failed.
    130      *
    131      * @return Whether the print job is blocked.
    132      *
    133      * @see #start()
    134      * @see #cancel()
    135      * @see #fail(CharSequence)
    136      */
    137     public boolean isBlocked() {
    138         PrintService.throwIfNotCalledOnMainThread();
    139         return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
    140     }
    141 
    142     /**
    143      * Gets whether this print job is completed. Such a print job
    144      * is successfully printed. This is a final state.
    145      *
    146      * @return Whether the print job is completed.
    147      *
    148      * @see #complete()
    149      */
    150     public boolean isCompleted() {
    151         PrintService.throwIfNotCalledOnMainThread();
    152         return getInfo().getState() == PrintJobInfo.STATE_COMPLETED;
    153     }
    154 
    155     /**
    156      * Gets whether this print job is failed. Such a print job is
    157      * not successfully printed due to an error. This is a final state.
    158      *
    159      * @return Whether the print job is failed.
    160      *
    161      * @see #fail(CharSequence)
    162      */
    163     public boolean isFailed() {
    164         PrintService.throwIfNotCalledOnMainThread();
    165         return getInfo().getState() == PrintJobInfo.STATE_FAILED;
    166     }
    167 
    168     /**
    169      * Gets whether this print job is cancelled. Such a print job was
    170      * cancelled as a result of a user request. This is a final state.
    171      *
    172      * @return Whether the print job is cancelled.
    173      *
    174      * @see #cancel()
    175      */
    176     public boolean isCancelled() {
    177         PrintService.throwIfNotCalledOnMainThread();
    178         return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
    179     }
    180 
    181     /**
    182      * Starts the print job. You should call this method if {@link
    183      * #isQueued()} or {@link #isBlocked()} returns true and you started
    184      * resumed printing.
    185      *
    186      * @return Whether the job was started.
    187      *
    188      * @see #isQueued()
    189      * @see #isBlocked()
    190      */
    191     public boolean start() {
    192         PrintService.throwIfNotCalledOnMainThread();
    193         final int state = getInfo().getState();
    194         if (state == PrintJobInfo.STATE_QUEUED
    195                 || state == PrintJobInfo.STATE_BLOCKED) {
    196             return setState(PrintJobInfo.STATE_STARTED, null);
    197         }
    198         return false;
    199     }
    200 
    201     /**
    202      * Blocks the print job. You should call this method if {@link
    203      * #isStarted()} or {@link #isBlocked()} returns true and you need
    204      * to block the print job. For example, the user has to add some
    205      * paper to continue printing. To resume the print job call {@link
    206      * #start()}.
    207      *
    208      * @return Whether the job was blocked.
    209      *
    210      * @see #isStarted()
    211      * @see #isBlocked()
    212      */
    213     public boolean block(String reason) {
    214         PrintService.throwIfNotCalledOnMainThread();
    215         PrintJobInfo info = getInfo();
    216         final int state = info.getState();
    217         if (state == PrintJobInfo.STATE_STARTED
    218                 || (state == PrintJobInfo.STATE_BLOCKED
    219                         && !TextUtils.equals(info.getStateReason(), reason))) {
    220             return setState(PrintJobInfo.STATE_BLOCKED, reason);
    221         }
    222         return false;
    223     }
    224 
    225     /**
    226      * Completes the print job. You should call this method if {@link
    227      * #isStarted()} returns true and you are done printing.
    228      *
    229      * @return Whether the job as completed.
    230      *
    231      * @see #isStarted()
    232      */
    233     public boolean complete() {
    234         PrintService.throwIfNotCalledOnMainThread();
    235         if (isStarted()) {
    236             return setState(PrintJobInfo.STATE_COMPLETED, null);
    237         }
    238         return false;
    239     }
    240 
    241     /**
    242      * Fails the print job. You should call this method if {@link
    243      * #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
    244      * returns true you failed while printing.
    245      *
    246      * @param error The human readable, short, and translated reason
    247      * for the failure.
    248      * @return Whether the job was failed.
    249      *
    250      * @see #isQueued()
    251      * @see #isStarted()
    252      * @see #isBlocked()
    253      */
    254     public boolean fail(String error) {
    255         PrintService.throwIfNotCalledOnMainThread();
    256         if (!isInImmutableState()) {
    257             return setState(PrintJobInfo.STATE_FAILED, error);
    258         }
    259         return false;
    260     }
    261 
    262     /**
    263      * Cancels the print job. You should call this method if {@link
    264      * #isQueued()} or {@link #isStarted() or #isBlocked()} returns
    265      * true and you canceled the print job as a response to a call to
    266      * {@link PrintService#onRequestCancelPrintJob(PrintJob)}.
    267      *
    268      * @return Whether the job is canceled.
    269      *
    270      * @see #isStarted()
    271      * @see #isQueued()
    272      * @see #isBlocked()
    273      */
    274     public boolean cancel() {
    275         PrintService.throwIfNotCalledOnMainThread();
    276         if (!isInImmutableState()) {
    277             return setState(PrintJobInfo.STATE_CANCELED, null);
    278         }
    279         return false;
    280     }
    281 
    282     /**
    283      * Sets a tag that is valid in the context of a {@link PrintService}
    284      * and is not interpreted by the system. For example, a print service
    285      * may set as a tag the key of the print job returned by a remote
    286      * print server, if the printing is off handed to a cloud based service.
    287      *
    288      * @param tag The tag.
    289      * @return True if the tag was set, false otherwise.
    290      */
    291     public boolean setTag(String tag) {
    292         PrintService.throwIfNotCalledOnMainThread();
    293         if (isInImmutableState()) {
    294             return false;
    295         }
    296         try {
    297             return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
    298         } catch (RemoteException re) {
    299             Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re);
    300         }
    301         return false;
    302     }
    303 
    304     /**
    305      * Gets the print job tag.
    306      *
    307      * @return The tag or null.
    308      *
    309      * @see #setTag(String)
    310      */
    311     public String getTag() {
    312         PrintService.throwIfNotCalledOnMainThread();
    313         return getInfo().getTag();
    314     }
    315 
    316     /**
    317      * Gets the value of an advanced (printer specific) print option.
    318      *
    319      * @param key The option key.
    320      * @return The option value.
    321      */
    322     public String getAdvancedStringOption(String key) {
    323         PrintService.throwIfNotCalledOnMainThread();
    324         return getInfo().getAdvancedStringOption(key);
    325     }
    326 
    327     /**
    328      * Gets whether this job has a given advanced (printer specific) print
    329      * option.
    330      *
    331      * @param key The option key.
    332      * @return Whether the option is present.
    333      */
    334     public boolean hasAdvancedOption(String key) {
    335         PrintService.throwIfNotCalledOnMainThread();
    336         return getInfo().hasAdvancedOption(key);
    337     }
    338 
    339     /**
    340      * Gets the value of an advanced (printer specific) print option.
    341      *
    342      * @param key The option key.
    343      * @return The option value.
    344      */
    345     public int getAdvancedIntOption(String key) {
    346         PrintService.throwIfNotCalledOnMainThread();
    347         return getInfo().getAdvancedIntOption(key);
    348     }
    349 
    350     @Override
    351     public boolean equals(Object obj) {
    352         if (this == obj) {
    353             return true;
    354         }
    355         if (obj == null) {
    356             return false;
    357         }
    358         if (getClass() != obj.getClass()) {
    359             return false;
    360         }
    361         PrintJob other = (PrintJob) obj;
    362         return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
    363     }
    364 
    365     @Override
    366     public int hashCode() {
    367         return mCachedInfo.getId().hashCode();
    368     }
    369 
    370     private boolean isInImmutableState() {
    371         final int state = mCachedInfo.getState();
    372         return state == PrintJobInfo.STATE_COMPLETED
    373                 || state == PrintJobInfo.STATE_CANCELED
    374                 || state == PrintJobInfo.STATE_FAILED;
    375     }
    376 
    377     private boolean setState(int state, String error) {
    378         try {
    379             if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state, error)) {
    380                 // Best effort - update the state of the cached info since
    381                 // we may not be able to re-fetch it later if the job gets
    382                 // removed from the spooler as a result of the state change.
    383                 mCachedInfo.setState(state);
    384                 mCachedInfo.setStateReason(error);
    385                 return true;
    386             }
    387         } catch (RemoteException re) {
    388             Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re);
    389         }
    390         return false;
    391     }
    392 }
    393