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