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.print;
18 
19 import android.os.Bundle;
20 import android.os.CancellationSignal;
21 import android.os.ParcelFileDescriptor;
22 
23 /**
24  * Base class that provides the content of a document to be printed.
25  *
26  * <h3>Lifecycle</h3>
27  * <p>
28  * <ul>
29  * <li>
30  * Initially, you will receive a call to {@link #onStart()}. This callback
31  * can be used to allocate resources.
32  * </li>
33  * <li>
34  * Next, you will get one or more calls to {@link #onLayout(PrintAttributes,
35  * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} to
36  * inform you that the print attributes (page size, density, etc) changed
37  * giving you an opportunity to layout the content to match the new constraints.
38  * </li>
39  * <li>
40  * After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
41  * CancellationSignal, LayoutResultCallback, Bundle)}, you <strong>may</strong> get
42  * a call to {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
43  * WriteResultCallback)} asking you to write a PDF file with the content for
44  * specific pages.
45  * </li>
46  * <li>
47  * Finally, you will receive a call to {@link #onFinish()}. You can use this
48  * callback to release resources allocated in {@link #onStart()}.
49  * </li>
50  * </ul>
51  * <p>
52  * The {@link #onStart()} callback is always the first call you will receive and
53  * is useful for doing one time setup or resource allocation before printing. You
54  * will not receive a subsequent call here.
55  * </p>
56  * <p>
57  * The {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
58  * LayoutResultCallback, Bundle)} callback requires that you layout the content
59  * based on the current {@link PrintAttributes}. The execution of this method is
60  * not considered completed until you invoke one of the methods on the passed in
61  * callback instance. Hence, you will not receive a subsequent call to any other
62  * method of this class until the execution of this method is complete by invoking
63  * one of the callback methods.
64  * </p>
65  * <p>
66  * The {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
67  * WriteResultCallback)} requires that you render and write the content of some
68  * pages to the provided destination. The execution of this method is not
69  * considered complete until you invoke one of the methods on the passed in
70  * callback instance. Hence, you will not receive a subsequent call to any other
71  * method of this class until the execution of this method is complete by invoking
72  * one of the callback methods. You will never receive a sequence of one or more
73  * calls to this method without a previous call to {@link #onLayout(PrintAttributes,
74  * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)}.
75  * </p>
76  * <p>
77  * The {@link #onFinish()} callback is always the last call you will receive and
78  * is useful for doing one time cleanup or resource deallocation after printing.
79  * You will not receive a subsequent call here.
80  * </p>
81  * </p>
82  * <h3>Implementation</h3>
83  * <p>
84  * The APIs defined in this class are designed to enable doing part or all
85  * of the work on an arbitrary thread. For example, if the printed content
86  * does not depend on the UI state, i.e. on what is shown on the screen, then
87  * you can offload the entire work on a dedicated thread, thus making your
88  * application interactive while the print work is being performed. Note that
89  * while your activity is covered by the system print UI and a user cannot
90  * interact with it, doing the printing work on the main application thread
91  * may affect the performance of your other application components as they
92  * are also executed on that thread.
93  * </p>
94  * <p>
95  * You can also do work on different threads, for example if you print UI
96  * content, you can handle {@link #onStart()} and {@link #onLayout(PrintAttributes,
97  * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on
98  * the UI thread (assuming onStart initializes resources needed for layout).
99  * This will ensure that the UI does not change while you are laying out the
100  * printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
101  * CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
102  * thread. This will ensure that the main thread is busy for a minimal amount of
103  * time. Also this assumes that you will generate the printed content in
104  * {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
105  * LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple
106  * threads, you are responsible for proper synchronization.
107  * </p>
108  */
109 public abstract class PrintDocumentAdapter {
110 
111     /**
112      * Extra: mapped to a boolean value that is <code>true</code> if
113      * the current layout is for a print preview, <code>false</code> otherwise.
114      * This extra is provided in the {@link Bundle} argument of the {@link
115      * #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
116      * LayoutResultCallback, Bundle)} callback.
117      *
118      * @see #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
119      * LayoutResultCallback, Bundle)
120      */
121     public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
122 
123     /**
124      * Called when printing starts. You can use this callback to allocate
125      * resources. This method is invoked on the main thread.
126      */
onStart()127     public void onStart() {
128         /* do nothing - stub */
129     }
130 
131     /**
132      * Called when the print attributes (page size, density, etc) changed
133      * giving you a chance to layout the content such that it matches the
134      * new constraints. This method is invoked on the main thread.
135      * <p>
136      * After you are done laying out, you <strong>must</strong> invoke: {@link
137      * LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with
138      * the last argument <code>true</code> or <code>false</code> depending on
139      * whether the layout changed the content or not, respectively; or {@link
140      * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred;
141      * or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
142      * cancelled in a response to a cancellation request via the passed in
143      * {@link CancellationSignal}. Note that you <strong>must</strong> call one of
144      * the methods of the given callback for this method to be considered complete
145      * which is you will not receive any calls to this adapter until the current
146      * layout operation is complete by invoking a method on the callback instance.
147      * The callback methods can be invoked from an arbitrary thread.
148      * </p>
149      * <p>
150      * One of the arguments passed to this method is a {@link CancellationSignal}
151      * which is used to propagate requests from the system to your application for
152      * canceling the current layout operation. For example, a cancellation may be
153      * requested if the user changes a print option that may affect layout while
154      * you are performing a layout operation. In such a case the system will make
155      * an attempt to cancel the current layout as another one will have to be performed.
156      * Typically, you should register a cancellation callback in the cancellation
157      * signal. The cancellation callback <strong>will not</strong> be made on the
158      * main thread and can be registered as follows:
159      * </p>
160      * <pre>
161      * cancellationSignal.setOnCancelListener(new OnCancelListener() {
162      *     &#064;Override
163      *     public void onCancel() {
164      *         // Cancel layout
165      *     }
166      * });
167      * </pre>
168      * <p>
169      * <strong>Note:</strong> If the content is large and a layout will be
170      * performed, it is a good practice to schedule the work on a dedicated
171      * thread and register an observer in the provided {@link
172      * CancellationSignal} upon invocation of which you should stop the
173      * layout.
174      * </p>
175      *
176      * @param oldAttributes The old print attributes.
177      * @param newAttributes The new print attributes.
178      * @param cancellationSignal Signal for observing cancel layout requests.
179      * @param callback Callback to inform the system for the layout result.
180      * @param extras Additional information about how to layout the content.
181      *
182      * @see LayoutResultCallback
183      * @see CancellationSignal
184      * @see #EXTRA_PRINT_PREVIEW
185      */
onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)186     public abstract void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
187             CancellationSignal cancellationSignal, LayoutResultCallback callback,
188             Bundle extras);
189 
190     /**
191      * Called when specific pages of the content should be written in the
192      * form of a PDF file to the given file descriptor. This method is invoked
193      * on the main thread.
194      *<p>
195      * After you are done writing, you should close the file descriptor and
196      * invoke {@link WriteResultCallback#onWriteFinished(PageRange[])}, if writing
197      * completed successfully; or {@link WriteResultCallback#onWriteFailed(
198      * CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
199      * if writing was cancelled in a response to a cancellation request via the passed
200      * in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
201      * the methods of the given callback for this method to be considered complete which
202      * is you will not receive any calls to this adapter until the current write
203      * operation is complete by invoking a method on the callback instance. The callback
204      * methods can be invoked from an arbitrary thread.
205      * </p>
206      * <p>
207      * One of the arguments passed to this method is a {@link CancellationSignal}
208      * which is used to propagate requests from the system to your application for
209      * canceling the current write operation. For example, a cancellation may be
210      * requested if the user changes a print option that may affect layout while
211      * you are performing a write operation. In such a case the system will make
212      * an attempt to cancel the current write as a layout will have to be performed
213      * which then may be followed by a write. Typically, you should register a
214      * cancellation callback in the cancellation signal. The cancellation callback
215      * <strong>will not</strong> be made on the main thread and can be registered
216      * as follows:
217      * </p>
218      * <pre>
219      * cancellationSignal.setOnCancelListener(new OnCancelListener() {
220      *     &#064;Override
221      *     public void onCancel() {
222      *         // Cancel write
223      *     }
224      * });
225      * </pre>
226      * <p>
227      * <strong>Note:</strong> If the printed content is large, it is a good
228      * practice to schedule writing it on a dedicated thread and register an
229      * observer in the provided {@link CancellationSignal} upon invocation of
230      * which you should stop writing.
231      * </p>
232      *
233      * @param pages The pages whose content to print - non-overlapping in ascending order.
234      * @param destination The destination file descriptor to which to write.
235      * @param cancellationSignal Signal for observing cancel writing requests.
236      * @param callback Callback to inform the system for the write result.
237      *
238      * @see WriteResultCallback
239      * @see CancellationSignal
240      */
onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)241     public abstract void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
242             CancellationSignal cancellationSignal, WriteResultCallback callback);
243 
244     /**
245      * Called when printing finishes. You can use this callback to release
246      * resources acquired in {@link #onStart()}. This method is invoked on
247      * the main thread.
248      */
onFinish()249     public void onFinish() {
250         /* do nothing - stub */
251     }
252 
253     /**
254      * Base class for implementing a callback for the result of {@link
255      * PrintDocumentAdapter#onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
256      * WriteResultCallback)}.
257      */
258     public static abstract class WriteResultCallback {
259 
260         /**
261          * @hide
262          */
WriteResultCallback()263         public WriteResultCallback() {
264             /* do nothing - hide constructor */
265         }
266 
267         /**
268          * Notifies that all the data was written.
269          *
270          * @param pages The pages that were written. Cannot be <code>null</code>
271          * or empty.
272          */
onWriteFinished(PageRange[] pages)273         public void onWriteFinished(PageRange[] pages) {
274             /* do nothing - stub */
275         }
276 
277         /**
278          * Notifies that an error occurred while writing the data.
279          *
280          * @param error The <strong>localized</strong> error message.
281          * shown to the user. May be <code>null</code> if error is unknown.
282          */
onWriteFailed(CharSequence error)283         public void onWriteFailed(CharSequence error) {
284             /* do nothing - stub */
285         }
286 
287         /**
288          * Notifies that write was cancelled as a result of a cancellation request.
289          */
onWriteCancelled()290         public void onWriteCancelled() {
291             /* do nothing - stub */
292         }
293     }
294 
295     /**
296      * Base class for implementing a callback for the result of {@link
297      * PrintDocumentAdapter#onLayout(PrintAttributes, PrintAttributes,
298      * CancellationSignal, LayoutResultCallback, Bundle)}.
299      */
300     public static abstract class LayoutResultCallback {
301 
302         /**
303          * @hide
304          */
LayoutResultCallback()305         public LayoutResultCallback() {
306             /* do nothing - hide constructor */
307         }
308 
309         /**
310          * Notifies that the layout finished and whether the content changed.
311          *
312          * @param info An info object describing the document. Cannot be <code>null</code>.
313          * @param changed Whether the layout changed.
314          *
315          * @see PrintDocumentInfo
316          */
onLayoutFinished(PrintDocumentInfo info, boolean changed)317         public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
318             /* do nothing - stub */
319         }
320 
321         /**
322          * Notifies that an error occurred while laying out the document.
323          *
324          * @param error The <strong>localized</strong> error message.
325          * shown to the user. May be <code>null</code> if error is unknown.
326          */
onLayoutFailed(CharSequence error)327         public void onLayoutFailed(CharSequence error) {
328             /* do nothing - stub */
329         }
330 
331         /**
332          * Notifies that layout was cancelled as a result of a cancellation request.
333          */
onLayoutCancelled()334         public void onLayoutCancelled() {
335             /* do nothing - stub */
336         }
337     }
338 }
339