blob: 6fa0bddb43f48e574c37111a67ed39f5e6a1c4bb [file] [log] [blame]
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -07001/*
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
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070019import android.os.RemoteException;
Svetoslav2fbd2a72013-09-16 17:53:51 -070020import android.print.PrintJobId;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070021import android.print.PrintJobInfo;
Svetoslav Ganovd26d4892013-08-28 14:37:54 -070022import android.text.TextUtils;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070023import android.util.Log;
24
25/**
Svetoslav Ganov798bed62013-08-11 12:29:39 -070026 * 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.
Svetoslav269403b2013-08-14 17:31:04 -070029 * <p>
Svetoslav Ganov99cc86f2013-08-29 21:37:10 -070030 * <strong>Note: </strong> All methods of this class must be invoked on
31 * the main application thread.
Svetoslav269403b2013-08-14 17:31:04 -070032 * </p>
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070033 */
34public final class PrintJob {
35
36 private static final String LOG_TAG = "PrintJob";
37
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070038 private final IPrintServiceClient mPrintServiceClient;
39
Svetoslav Ganova0027152013-06-25 14:59:53 -070040 private final PrintDocument mDocument;
41
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070042 private PrintJobInfo mCachedInfo;
43
Svetoslav Ganova0027152013-06-25 14:59:53 -070044 PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
45 mCachedInfo = jobInfo;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070046 mPrintServiceClient = client;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070047 mDocument = new PrintDocument(mCachedInfo.getId(), client,
48 jobInfo.getDocumentInfo());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070049 }
50
51 /**
52 * Gets the unique print job id.
53 *
54 * @return The id.
55 */
Svetoslav2fbd2a72013-09-16 17:53:51 -070056 public PrintJobId getId() {
Svetoslav269403b2013-08-14 17:31:04 -070057 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -070058 return mCachedInfo.getId();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070059 }
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
Svetoslavfd906512013-06-24 09:04:48 -070066 * info object that reflects the current print job state.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070067 * </p>
68 *
69 * @return The print job info.
70 */
71 public PrintJobInfo getInfo() {
Svetoslav269403b2013-08-14 17:31:04 -070072 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov85b1f882013-07-24 17:00:06 -070073 if (isInImmutableState()) {
74 return mCachedInfo;
75 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070076 PrintJobInfo info = null;
77 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -070078 info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070079 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -070080 Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070081 }
82 if (info != null) {
83 mCachedInfo = info;
84 }
85 return mCachedInfo;
86 }
87
88 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -070089 * Gets the printed document.
Svetoslav Ganova0027152013-06-25 14:59:53 -070090 *
91 * @return The document.
92 */
93 public PrintDocument getDocument() {
Svetoslav269403b2013-08-14 17:31:04 -070094 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -070095 return mDocument;
96 }
97
98 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070099 * Gets whether this print job is queued. Such a print job is
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700100 * ready to be printed and can be started or cancelled.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700101 *
102 * @return Whether the print job is queued.
103 *
104 * @see #start()
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700105 * @see #cancel()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700106 */
107 public boolean isQueued() {
Svetoslav269403b2013-08-14 17:31:04 -0700108 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700109 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()
Svetoslavfd906512013-06-24 09:04:48 -0700120 * @see #fail(CharSequence)
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700121 */
122 public boolean isStarted() {
Svetoslav269403b2013-08-14 17:31:04 -0700123 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -0700124 return getInfo().getState() == PrintJobInfo.STATE_STARTED;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700125 }
126
127 /**
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700128 * 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 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700143 * 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700151 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700152 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700164 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700165 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700177 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov704697b2013-09-21 20:30:24 -0700178 return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700179 }
180
181 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700182 * Starts the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700183 * #isQueued()} or {@link #isBlocked()} returns true and you started
184 * resumed printing.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700185 *
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700186 * @return Whether the job was started.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700187 *
188 * @see #isQueued()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700189 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700190 */
191 public boolean start() {
Svetoslav269403b2013-08-14 17:31:04 -0700192 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700193 final int state = getInfo().getState();
194 if (state == PrintJobInfo.STATE_QUEUED
195 || state == PrintJobInfo.STATE_BLOCKED) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700196 return setState(PrintJobInfo.STATE_STARTED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700197 }
198 return false;
199 }
200
201 /**
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700202 * 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 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700226 * 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700234 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700235 if (isStarted()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700236 return setState(PrintJobInfo.STATE_COMPLETED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700237 }
238 return false;
239 }
240
241 /**
242 * Fails the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700243 * #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
244 * returns true you failed while printing.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700245 *
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700246 * @param error The human readable, short, and translated reason
247 * for the failure.
Svetoslavfd906512013-06-24 09:04:48 -0700248 * @return Whether the job was failed.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700249 *
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700250 * @see #isQueued()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700251 * @see #isStarted()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700252 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700253 */
Svetoslav269403b2013-08-14 17:31:04 -0700254 public boolean fail(String error) {
255 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700256 if (!isInImmutableState()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700257 return setState(PrintJobInfo.STATE_FAILED, error);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700258 }
259 return false;
260 }
261
262 /**
263 * Cancels the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700264 * #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)}.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700267 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700268 * @return Whether the job is canceled.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700269 *
270 * @see #isStarted()
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700271 * @see #isQueued()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700272 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700273 */
274 public boolean cancel() {
Svetoslav269403b2013-08-14 17:31:04 -0700275 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700276 if (!isInImmutableState()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700277 return setState(PrintJobInfo.STATE_CANCELED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700278 }
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) {
Svetoslav269403b2013-08-14 17:31:04 -0700292 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700293 if (isInImmutableState()) {
294 return false;
295 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700296 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700297 return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700298 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700299 Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700300 }
301 return false;
302 }
303
Svetoslavb450d0d2013-10-04 16:20:00 -0700304 /**
305 * Gets the print job tag.
306 *
Svetoslav1c43fce2013-10-16 10:57:48 -0700307 * @return The tag or null.
Svetoslavb450d0d2013-10-04 16:20:00 -0700308 *
309 * @see #setTag(String)
310 */
311 public String getTag() {
312 PrintService.throwIfNotCalledOnMainThread();
313 return getInfo().getTag();
314 }
315
Svetoslav1c43fce2013-10-16 10:57:48 -0700316 /**
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();
Svetoslavb4fda132013-10-25 18:57:43 -0700324 return getInfo().getAdvancedStringOption(key);
Svetoslav1c43fce2013-10-16 10:57:48 -0700325 }
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();
Svetoslavb4fda132013-10-25 18:57:43 -0700336 return getInfo().hasAdvancedOption(key);
Svetoslav1c43fce2013-10-16 10:57:48 -0700337 }
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();
Svetoslavb4fda132013-10-25 18:57:43 -0700347 return getInfo().getAdvancedIntOption(key);
Svetoslav1c43fce2013-10-16 10:57:48 -0700348 }
349
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700350 @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;
Svetoslav2fbd2a72013-09-16 17:53:51 -0700362 return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700363 }
364
365 @Override
366 public int hashCode() {
Svetoslav2fbd2a72013-09-16 17:53:51 -0700367 return mCachedInfo.getId().hashCode();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700368 }
369
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700370 private boolean isInImmutableState() {
371 final int state = mCachedInfo.getState();
372 return state == PrintJobInfo.STATE_COMPLETED
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700373 || state == PrintJobInfo.STATE_CANCELED
374 || state == PrintJobInfo.STATE_FAILED;
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700375 }
376
Svetoslav269403b2013-08-14 17:31:04 -0700377 private boolean setState(int state, String error) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700378 try {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700379 if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state, error)) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700380 // 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);
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700384 mCachedInfo.setStateReason(error);
Svetoslav Ganova0027152013-06-25 14:59:53 -0700385 return true;
386 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700387 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700388 Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700389 }
390 return false;
391 }
392}