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.annotation.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.text.TextUtils;
25 import com.android.internal.util.Preconditions;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 
30 /**
31  * This class encapsulates information about a document for printing
32  * purposes. This meta-data is used by the platform and print services,
33  * components that interact with printers. For example, this class
34  * contains the number of pages contained in the document it describes and
35  * this number of pages is shown to the user allowing him/her to select
36  * the range to print. Also a print service may optimize the printing
37  * process based on the content type, such as document or photo.
38  * <p>
39  * Instances of this class are created by the printing application and
40  * passed to the {@link PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished(
41  * PrintDocumentInfo, boolean) PrintDocumentAdapter.LayoutResultCallback.onLayoutFinished(
42  * PrintDocumentInfo, boolean)} callback after successfully laying out the
43  * content which is performed in {@link PrintDocumentAdapter#onLayout(PrintAttributes,
44  * PrintAttributes, android.os.CancellationSignal, PrintDocumentAdapter.LayoutResultCallback,
45  * android.os.Bundle) PrintDocumentAdapter.onLayout(PrintAttributes,
46  * PrintAttributes, android.os.CancellationSignal,
47  * PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle)}.
48  * </p>
49  * <p>
50  * An example usage looks like this:
51  * <pre>
52  *
53  * . . .
54  *
55  * public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
56  *         CancellationSignal cancellationSignal, LayoutResultCallback callback,
57  *         Bundle metadata) {
58  *
59  *        // Assume the app defined a LayoutResult class which contains
60  *        // the layout result data and that the content is a document.
61  *        LayoutResult result = doSomeLayoutWork();
62  *
63  *        PrintDocumentInfo info = new PrintDocumentInfo
64  *                .Builder("printed_file.pdf")
65  *                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
66  *                .setPageCount(result.getPageCount())
67  *                .build();
68  *
69  *       callback.onLayoutFinished(info, result.getContentChanged());
70  *   }
71  *
72  *   . . .
73  *
74  * </pre>
75  * </p>
76  */
77 public final class PrintDocumentInfo implements Parcelable {
78 
79     /**
80      * Constant for unknown page count.
81      */
82     public static final int PAGE_COUNT_UNKNOWN = -1;
83 
84     /** @hide */
85     @Retention(RetentionPolicy.SOURCE)
86     @IntDef({
87             CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
88     })
89     public @interface ContentType {
90     }
91     /**
92      * Content type: unknown.
93      */
94     public static final int CONTENT_TYPE_UNKNOWN = -1;
95 
96     /**
97      * Content type: document.
98      * <p>
99      * A print service may use normal paper to print the content instead
100      * of dedicated photo paper. Also it may use a lower quality printing
101      * process as the content is not as sensitive to print quality variation
102      * as a photo is.
103      * </p>
104      */
105     public static final int CONTENT_TYPE_DOCUMENT = 0;
106 
107     /**
108      * Content type: photo.
109      * <p>
110      * A print service may use dedicated photo paper to print the content
111      * instead of normal paper. Also it may use a higher quality printing
112      * process as the content is more sensitive to print quality variation
113      * than a document.
114      * </p>
115      */
116     public static final int CONTENT_TYPE_PHOTO = 1;
117 
118     private @NonNull String mName;
119     private @IntRange(from = -1) int mPageCount;
120     private int mContentType;
121     private long mDataSize;
122 
123     /**
124      * Creates a new instance.
125      */
PrintDocumentInfo()126     private PrintDocumentInfo() {
127         /* do nothing */
128     }
129 
130     /**
131      * Creates a new instance.
132      *
133      * @param prototype from which to clone.
134      */
PrintDocumentInfo(@onNull PrintDocumentInfo prototype)135     private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
136         mName = prototype.mName;
137         mPageCount = prototype.mPageCount;
138         mContentType = prototype.mContentType;
139         mDataSize = prototype.mDataSize;
140     }
141 
142     /**
143      * Creates a new instance.
144      *
145      * @param parcel Data from which to initialize.
146      */
PrintDocumentInfo(Parcel parcel)147     private PrintDocumentInfo(Parcel parcel) {
148         mName = Preconditions.checkStringNotEmpty(parcel.readString());
149         mPageCount = parcel.readInt();
150         Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
151         mContentType = parcel.readInt();
152         mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
153     }
154 
155     /**
156      * Gets the document name. This name may be shown to
157      * the user.
158      *
159      * @return The document name.
160      */
getName()161     public @NonNull String getName() {
162         return mName;
163     }
164 
165     /**
166      * Gets the total number of pages.
167      *
168      * @return The number of pages.
169      *
170      * @see #PAGE_COUNT_UNKNOWN
171      */
getPageCount()172     public @IntRange(from = -1) int getPageCount() {
173         return mPageCount;
174     }
175 
176     /**
177      * Gets the content type.
178      *
179      * @return The content type.
180      *
181      * @see #CONTENT_TYPE_UNKNOWN
182      * @see #CONTENT_TYPE_DOCUMENT
183      * @see #CONTENT_TYPE_PHOTO
184      */
getContentType()185     public int getContentType() {
186         return mContentType;
187     }
188 
189     /**
190      * Gets the document data size in bytes.
191      *
192      * @return The data size.
193      */
getDataSize()194     public @IntRange(from = 0) long getDataSize() {
195         return mDataSize;
196     }
197 
198     /**
199      * Sets the document data size in bytes.
200      *
201      * @param dataSize The data size.
202      *
203      * @hide
204      */
setDataSize(@ntRangefrom = 0) long dataSize)205     public void setDataSize(@IntRange(from = 0) long dataSize) {
206         mDataSize = dataSize;
207     }
208 
209     @Override
describeContents()210     public int describeContents() {
211         return 0;
212     }
213 
214     @Override
writeToParcel(Parcel parcel, int flags)215     public void writeToParcel(Parcel parcel, int flags) {
216         parcel.writeString(mName);
217         parcel.writeInt(mPageCount);
218         parcel.writeInt(mContentType);
219         parcel.writeLong(mDataSize);
220     }
221 
222     @Override
hashCode()223     public int hashCode() {
224         final int prime = 31;
225         int result = 1;
226         result = prime * result + ((mName != null) ? mName.hashCode() : 0);
227         result = prime * result + mContentType;
228         result = prime * result + mPageCount;
229         result = prime * result + (int) mDataSize;
230         result = prime * result + (int) (mDataSize >> 32);
231         return result;
232     }
233 
234     @Override
equals(Object obj)235     public boolean equals(Object obj) {
236         if (this == obj) {
237             return true;
238         }
239         if (obj == null) {
240             return false;
241         }
242         if (getClass() != obj.getClass()) {
243             return false;
244         }
245         PrintDocumentInfo other = (PrintDocumentInfo) obj;
246         if (!TextUtils.equals(mName, other.mName)) {
247             return false;
248         }
249         if (mContentType != other.mContentType) {
250             return false;
251         }
252         if (mPageCount != other.mPageCount) {
253             return false;
254         }
255         if (mDataSize != other.mDataSize) {
256             return false;
257         }
258         return true;
259     }
260 
261     @Override
toString()262     public String toString() {
263         StringBuilder builder = new StringBuilder();
264         builder.append("PrintDocumentInfo{");
265         builder.append("name=").append(mName);
266         builder.append(", pageCount=").append(mPageCount);
267         builder.append(", contentType=").append(contentTypeToString(mContentType));
268         builder.append(", dataSize=").append(mDataSize);
269         builder.append("}");
270         return builder.toString();
271     }
272 
contentTypeToString(int contentType)273     private String contentTypeToString(int contentType) {
274         switch (contentType) {
275             case CONTENT_TYPE_DOCUMENT: {
276                 return "CONTENT_TYPE_DOCUMENT";
277             }
278             case CONTENT_TYPE_PHOTO: {
279                 return "CONTENT_TYPE_PHOTO";
280             }
281             default: {
282                 return "CONTENT_TYPE_UNKNOWN";
283             }
284         }
285     }
286 
287     /**
288      * Builder for creating a {@link PrintDocumentInfo}.
289      */
290     public static final class Builder {
291         private final PrintDocumentInfo mPrototype;
292 
293         /**
294          * Constructor.
295          *
296          * <p>
297          * The values of the relevant properties are initialized with defaults.
298          * Please refer to the documentation of the individual setters for
299          * information about the default values.
300          * </p>
301          *
302          * @param name The document name which may be shown to the user and
303          * is the file name if the content it describes is saved as a PDF.
304          * Cannot be empty.
305          */
Builder(@onNull String name)306         public Builder(@NonNull String name) {
307             if (TextUtils.isEmpty(name)) {
308                 throw new IllegalArgumentException("name cannot be empty");
309             }
310             mPrototype = new PrintDocumentInfo();
311             mPrototype.mName = name;
312         }
313 
314         /**
315          * Sets the total number of pages.
316          * <p>
317          * <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
318          * </p>
319          *
320          * @param pageCount The number of pages. Must be greater than or equal to zero or
321          *            {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
322          * @return This builder.
323          */
setPageCount(@ntRangefrom = -1) int pageCount)324         public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
325             if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
326                 throw new IllegalArgumentException("pageCount"
327                         + " must be greater than or equal to zero or"
328                         + " DocumentInfo#PAGE_COUNT_UNKNOWN");
329             }
330             mPrototype.mPageCount = pageCount;
331             return this;
332         }
333 
334         /**
335          * Sets the content type.
336          * <p>
337          * <strong>Default: </strong> {@link #CONTENT_TYPE_DOCUMENT}
338          * </p>
339          *
340          * @param type The content type.
341          * @return This builder.
342          * @see #CONTENT_TYPE_UNKNOWN
343          * @see #CONTENT_TYPE_DOCUMENT
344          * @see #CONTENT_TYPE_PHOTO
345          */
setContentType(@ontentType int type)346         public @NonNull Builder setContentType(@ContentType int type) {
347             mPrototype.mContentType = type;
348             return this;
349         }
350 
351         /**
352          * Creates a new {@link PrintDocumentInfo} instance.
353          *
354          * @return The new instance.
355          */
build()356         public @NonNull PrintDocumentInfo build() {
357             // Zero pages is the same as unknown as in this case
358             // we will have to ask for all pages and look a the
359             // wiritten PDF file for the page count.
360             if (mPrototype.mPageCount == 0) {
361                 mPrototype.mPageCount = PAGE_COUNT_UNKNOWN;
362             }
363             return new PrintDocumentInfo(mPrototype);
364         }
365     }
366 
367     public static final Parcelable.Creator<PrintDocumentInfo> CREATOR =
368             new Creator<PrintDocumentInfo>() {
369         @Override
370         public PrintDocumentInfo createFromParcel(Parcel parcel) {
371             return new PrintDocumentInfo(parcel);
372         }
373 
374         @Override
375         public PrintDocumentInfo[] newArray(int size) {
376             return new PrintDocumentInfo[size];
377         }
378     };
379 }
380