blob: 8bae9d67757211a17c564612815e8152ecffb6f8 [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;
20import android.print.PrintJobInfo;
Svetoslav Ganovd26d4892013-08-28 14:37:54 -070021import android.text.TextUtils;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070022import android.util.Log;
23
24/**
Svetoslav Ganov798bed62013-08-11 12:29:39 -070025 * 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.
Svetoslav269403b2013-08-14 17:31:04 -070028 * <p>
29 * <strong>Note: </strong> All methods of this class must be executed on the main
30 * application thread.
31 * </p>
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070032 */
33public final class PrintJob {
34
35 private static final String LOG_TAG = "PrintJob";
36
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070037 private final IPrintServiceClient mPrintServiceClient;
38
Svetoslav Ganova0027152013-06-25 14:59:53 -070039 private final PrintDocument mDocument;
40
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070041 private PrintJobInfo mCachedInfo;
42
Svetoslav Ganova0027152013-06-25 14:59:53 -070043 PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
44 mCachedInfo = jobInfo;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070045 mPrintServiceClient = client;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070046 mDocument = new PrintDocument(mCachedInfo.getId(), client,
47 jobInfo.getDocumentInfo());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070048 }
49
50 /**
51 * Gets the unique print job id.
52 *
53 * @return The id.
54 */
55 public int getId() {
Svetoslav269403b2013-08-14 17:31:04 -070056 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -070057 return mCachedInfo.getId();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070058 }
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
Svetoslavfd906512013-06-24 09:04:48 -070065 * info object that reflects the current print job state.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070066 * </p>
67 *
68 * @return The print job info.
69 */
70 public PrintJobInfo getInfo() {
Svetoslav269403b2013-08-14 17:31:04 -070071 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov85b1f882013-07-24 17:00:06 -070072 if (isInImmutableState()) {
73 return mCachedInfo;
74 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070075 PrintJobInfo info = null;
76 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -070077 info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070078 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -070079 Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070080 }
81 if (info != null) {
82 mCachedInfo = info;
83 }
84 return mCachedInfo;
85 }
86
87 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -070088 * Gets the printed document.
Svetoslav Ganova0027152013-06-25 14:59:53 -070089 *
90 * @return The document.
91 */
92 public PrintDocument getDocument() {
Svetoslav269403b2013-08-14 17:31:04 -070093 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -070094 return mDocument;
95 }
96
97 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070098 * Gets whether this print job is queued. Such a print job is
Svetoslav Ganov798bed62013-08-11 12:29:39 -070099 * ready to be printed and can be started or cancelled.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700100 *
101 * @return Whether the print job is queued.
102 *
103 * @see #start()
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700104 * @see #cancel()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700105 */
106 public boolean isQueued() {
Svetoslav269403b2013-08-14 17:31:04 -0700107 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700108 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()
Svetoslavfd906512013-06-24 09:04:48 -0700119 * @see #fail(CharSequence)
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700120 */
121 public boolean isStarted() {
Svetoslav269403b2013-08-14 17:31:04 -0700122 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganova0027152013-06-25 14:59:53 -0700123 return getInfo().getState() == PrintJobInfo.STATE_STARTED;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700124 }
125
126 /**
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700127 * 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 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700142 * 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700150 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700151 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700163 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700164 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700176 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700177 return getInfo().getState() == PrintJobInfo.STATE_FAILED;
178 }
179
180 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700181 * Starts the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700182 * #isQueued()} or {@link #isBlocked()} returns true and you started
183 * resumed printing.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700184 *
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700185 * @return Whether the job was started.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700186 *
187 * @see #isQueued()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700188 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700189 */
190 public boolean start() {
Svetoslav269403b2013-08-14 17:31:04 -0700191 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700192 final int state = getInfo().getState();
193 if (state == PrintJobInfo.STATE_QUEUED
194 || state == PrintJobInfo.STATE_BLOCKED) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700195 return setState(PrintJobInfo.STATE_STARTED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700196 }
197 return false;
198 }
199
200 /**
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700201 * 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 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700225 * 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() {
Svetoslav269403b2013-08-14 17:31:04 -0700233 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700234 if (isStarted()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700235 return setState(PrintJobInfo.STATE_COMPLETED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700236 }
237 return false;
238 }
239
240 /**
241 * Fails the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700242 * #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
243 * returns true you failed while printing.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700244 *
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700245 * @param error The human readable, short, and translated reason
246 * for the failure.
Svetoslavfd906512013-06-24 09:04:48 -0700247 * @return Whether the job was failed.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700248 *
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700249 * @see #isQueued()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700250 * @see #isStarted()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700251 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700252 */
Svetoslav269403b2013-08-14 17:31:04 -0700253 public boolean fail(String error) {
254 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700255 if (!isInImmutableState()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700256 return setState(PrintJobInfo.STATE_FAILED, error);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700257 }
258 return false;
259 }
260
261 /**
262 * Cancels the print job. You should call this method if {@link
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700263 * #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)}.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700266 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700267 * @return Whether the job is canceled.
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700268 *
269 * @see #isStarted()
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700270 * @see #isQueued()
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700271 * @see #isBlocked()
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700272 */
273 public boolean cancel() {
Svetoslav269403b2013-08-14 17:31:04 -0700274 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700275 if (!isInImmutableState()) {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700276 return setState(PrintJobInfo.STATE_CANCELED, null);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700277 }
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) {
Svetoslav269403b2013-08-14 17:31:04 -0700291 PrintService.throwIfNotCalledOnMainThread();
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700292 if (isInImmutableState()) {
293 return false;
294 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700295 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700296 return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700297 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700298 Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700299 }
300 return false;
301 }
302
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700303 @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;
Svetoslav Ganova0027152013-06-25 14:59:53 -0700315 return (mCachedInfo.getId() == other.mCachedInfo.getId());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700316 }
317
318 @Override
319 public int hashCode() {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700320 return mCachedInfo.getId();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700321 }
322
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700323 private boolean isInImmutableState() {
324 final int state = mCachedInfo.getState();
325 return state == PrintJobInfo.STATE_COMPLETED
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700326 || state == PrintJobInfo.STATE_CANCELED
327 || state == PrintJobInfo.STATE_FAILED;
Svetoslav Ganov85b1f882013-07-24 17:00:06 -0700328 }
329
Svetoslav269403b2013-08-14 17:31:04 -0700330 private boolean setState(int state, String error) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700331 try {
Svetoslav Ganov8c433762013-08-02 14:22:19 -0700332 if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state, error)) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700333 // 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);
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700337 mCachedInfo.setStateReason(error);
Svetoslav Ganova0027152013-06-25 14:59:53 -0700338 return true;
339 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700340 } catch (RemoteException re) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700341 Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700342 }
343 return false;
344 }
345}