PrintJob.java revision fd90651cfcc7e2b75254666fd6861038b72fb4ac
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 java.io.FileDescriptor;
20import java.io.IOException;
21
22import android.os.ParcelFileDescriptor;
23import android.os.RemoteException;
24import android.print.PrintJobInfo;
25import android.util.Log;
26
27/**
28 * This class represents a print job from the perspective of a
29 * print service. It provides APIs for observing the print job
30 * state and performing operations on the print job.
31 */
32public final class PrintJob {
33
34    private static final String LOG_TAG = "PrintJob";
35
36    private final int mId;
37
38    private final IPrintServiceClient mPrintServiceClient;
39
40    private PrintJobInfo mCachedInfo;
41
42    PrintJob(PrintJobInfo info, IPrintServiceClient client) {
43        if (client == null) {
44            throw new IllegalStateException("Print serivice not connected!");
45        }
46        mCachedInfo = info;
47        mId = info.getId();
48        mPrintServiceClient = client;
49    }
50
51    /**
52     * Gets the unique print job id.
53     *
54     * @return The id.
55     */
56    public int getId() {
57        return mId;
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        PrintJobInfo info = null;
72        try {
73            info = mPrintServiceClient.getPrintJob(mId);
74        } catch (RemoteException re) {
75            Log.e(LOG_TAG, "Couldn't get info for job: " + mId, re);
76        }
77        if (info != null) {
78            mCachedInfo = info;
79        }
80        return mCachedInfo;
81    }
82
83    /**
84     * Gets whether this print job is queued. Such a print job is
85     * ready to be printed and can be started.
86     *
87     * @return Whether the print job is queued.
88     *
89     * @see #start()
90     */
91    public boolean isQueued() {
92        return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
93    }
94
95    /**
96     * Gets whether this print job is started. Such a print job is
97     * being printed and can be completed or canceled or failed.
98     *
99     * @return Whether the print job is started.
100     *
101     * @see #complete()
102     * @see #cancel()
103     * @see #fail(CharSequence)
104     */
105    public boolean isStarted() {
106        return  getInfo().getState() == PrintJobInfo.STATE_STARTED;
107    }
108
109    /**
110     * Starts the print job. You should call this method if {@link
111     * #isQueued()} returns true and you started printing.
112     *
113     * @return Whether the job as started.
114     *
115     * @see #isQueued()
116     */
117    public boolean start() {
118        if (isQueued()) {
119            return setState(PrintJobInfo.STATE_STARTED);
120        }
121        return false;
122    }
123
124    /**
125     * Completes the print job. You should call this method if {@link
126     * #isStarted()} returns true and you are done printing.
127     *
128     * @return Whether the job as completed.
129     *
130     * @see #isStarted()
131     */
132    public boolean complete() {
133        if (isStarted()) {
134            return setState(PrintJobInfo.STATE_COMPLETED);
135        }
136        return false;
137    }
138
139    /**
140     * Fails the print job. You should call this method if {@link
141     * #isStarted()} returns true you filed while printing.
142     *
143     * @param error The reason for the failure.
144     * @return Whether the job was failed.
145     *
146     * @see #isStarted()
147     */
148    public boolean fail(CharSequence error) {
149        // TODO: Propagate the error message to the UI.
150        if (isStarted()) {
151            return setState(PrintJobInfo.STATE_FAILED);
152        }
153        return false;
154    }
155
156    /**
157     * Cancels the print job. You should call this method if {@link
158     * #isStarted()} returns true and you canceled the print job as a
159     * response to a call to {@link PrintService#onRequestCancelPrintJob(
160     * PrintJob)}.
161     *
162     * @return Whether the job as canceled.
163     *
164     * @see #isStarted()
165     */
166    public boolean cancel() {
167        if (isStarted()) {
168            return setState(PrintJobInfo.STATE_CANCELED);
169        }
170        return false;
171    }
172
173    /**
174     * Sets a tag that is valid in the context of a {@link PrintService}
175     * and is not interpreted by the system. For example, a print service
176     * may set as a tag the key of the print job returned by a remote
177     * print server, if the printing is off handed to a cloud based service.
178     *
179     * @param tag The tag.
180     * @return True if the tag was set, false otherwise.
181     */
182    public boolean setTag(String tag) {
183        try {
184            return mPrintServiceClient.setPrintJobTag(mId, tag);
185        } catch (RemoteException re) {
186            Log.e(LOG_TAG, "Error setting tag for job:" + mId, re);
187        }
188        return false;
189    }
190
191    /**
192     * Gets the data associated with this print job. It is a responsibility of
193     * the print service to open a stream to the returned file descriptor
194     * and fully read the content.
195     * <p>
196     * <strong>Note:</strong> It is your responsibility to close the file descriptor.
197     * </p>
198     *
199     * @return A file descriptor for reading the data or <code>null</code>.
200     */
201    public final FileDescriptor getData() {
202        ParcelFileDescriptor source = null;
203        ParcelFileDescriptor sink = null;
204        try {
205            ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
206            source = fds[0];
207            sink = fds[1];
208            mPrintServiceClient.writePrintJobData(sink, mId);
209            return source.getFileDescriptor();
210        } catch (IOException ioe) {
211            Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
212        } catch (RemoteException re) {
213            Log.e(LOG_TAG, "Error calling getting print job data!", re);
214        } finally {
215            if (sink != null) {
216                try {
217                    sink.close();
218                } catch (IOException ioe) {
219                    /* ignore */
220                }
221            }
222        }
223        return null;
224    }
225
226    @Override
227    public boolean equals(Object obj) {
228        if (this == obj) {
229            return true;
230        }
231        if (obj == null) {
232            return false;
233        }
234        if (getClass() != obj.getClass()) {
235            return false;
236        }
237        PrintJob other = (PrintJob) obj;
238        return (mId == other.mId);
239    }
240
241    @Override
242    public int hashCode() {
243        return mId;
244    }
245
246    private boolean setState(int state) {
247        // Best effort - update the state of the cached info since
248        // we may not be able to re-fetch it later if the job gets
249        // removed from the spooler.
250        mCachedInfo.setState(state);
251        try {
252            return mPrintServiceClient.setPrintJobState(mId, state);
253        } catch (RemoteException re) {
254            Log.e(LOG_TAG, "Error setting the state of job:" + mId, re);
255        }
256        return false;
257    }
258}
259