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