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(prefix = { "CONTENT_TYPE_" }, value = {
87             CONTENT_TYPE_UNKNOWN,
88             CONTENT_TYPE_DOCUMENT,
89             CONTENT_TYPE_PHOTO
90     })
91     public @interface ContentType {
92     }
93 
94     /**
95      * Content type: unknown.
96      */
97     public static final int CONTENT_TYPE_UNKNOWN = -1;
98 
99     /**
100      * Content type: document.
101      * <p>
102      * A print service may use normal paper to print the content instead
103      * of dedicated photo paper. Also it may use a lower quality printing
104      * process as the content is not as sensitive to print quality variation
105      * as a photo is.
106      * </p>
107      */
108     public static final int CONTENT_TYPE_DOCUMENT = 0;
109 
110     /**
111      * Content type: photo.
112      * <p>
113      * A print service may use dedicated photo paper to print the content
114      * instead of normal paper. Also it may use a higher quality printing
115      * process as the content is more sensitive to print quality variation
116      * than a document.
117      * </p>
118      */
119     public static final int CONTENT_TYPE_PHOTO = 1;
120 
121     private @NonNull String mName;
122     private @IntRange(from = -1) int mPageCount;
123     private int mContentType;
124     private long mDataSize;
125 
126     /**
127      * Creates a new instance.
128      */
PrintDocumentInfo()129     private PrintDocumentInfo() {
130         /* do nothing */
131     }
132 
133     /**
134      * Creates a new instance.
135      *
136      * @param prototype from which to clone.
137      */
PrintDocumentInfo(@onNull PrintDocumentInfo prototype)138     private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
139         mName = prototype.mName;
140         mPageCount = prototype.mPageCount;
141         mContentType = prototype.mContentType;
142         mDataSize = prototype.mDataSize;
143     }
144 
145     /**
146      * Creates a new instance.
147      *
148      * @param parcel Data from which to initialize.
149      */
PrintDocumentInfo(Parcel parcel)150     private PrintDocumentInfo(Parcel parcel) {
151         mName = Preconditions.checkStringNotEmpty(parcel.readString());
152         mPageCount = parcel.readInt();
153         Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
154         mContentType = parcel.readInt();
155         mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
156     }
157 
158     /**
159      * Gets the document name. This name may be shown to
160      * the user.
161      *
162      * @return The document name.
163      */
getName()164     public @NonNull String getName() {
165         return mName;
166     }
167 
168     /**
169      * Gets the total number of pages.
170      *
171      * @return The number of pages.
172      *
173      * @see #PAGE_COUNT_UNKNOWN
174      */
getPageCount()175     public @IntRange(from = -1) int getPageCount() {
176         return mPageCount;
177     }
178 
179     /**
180      * Gets the content type.
181      *
182      * @return The content type.
183      *
184      * @see #CONTENT_TYPE_UNKNOWN
185      * @see #CONTENT_TYPE_DOCUMENT
186      * @see #CONTENT_TYPE_PHOTO
187      */
getContentType()188     public int getContentType() {
189         return mContentType;
190     }
191 
192     /**
193      * Gets the document data size in bytes.
194      *
195      * @return The data size.
196      */
getDataSize()197     public @IntRange(from = 0) long getDataSize() {
198         return mDataSize;
199     }
200 
201     /**
202      * Sets the document data size in bytes.
203      *
204      * @param dataSize The data size.
205      *
206      * @hide
207      */
setDataSize(@ntRangefrom = 0) long dataSize)208     public void setDataSize(@IntRange(from = 0) long dataSize) {
209         mDataSize = dataSize;
210     }
211 
212     @Override
describeContents()213     public int describeContents() {
214         return 0;
215     }
216 
217     @Override
writeToParcel(Parcel parcel, int flags)218     public void writeToParcel(Parcel parcel, int flags) {
219         parcel.writeString(mName);
220         parcel.writeInt(mPageCount);
221         parcel.writeInt(mContentType);
222         parcel.writeLong(mDataSize);
223     }
224 
225     @Override
hashCode()226     public int hashCode() {
227         final int prime = 31;
228         int result = 1;
229         result = prime * result + ((mName != null) ? mName.hashCode() : 0);
230         result = prime * result + mContentType;
231         result = prime * result + mPageCount;
232         result = prime * result + (int) mDataSize;
233         result = prime * result + (int) (mDataSize >> 32);
234         return result;
235     }
236 
237     @Override
equals(Object obj)238     public boolean equals(Object obj) {
239         if (this == obj) {
240             return true;
241         }
242         if (obj == null) {
243             return false;
244         }
245         if (getClass() != obj.getClass()) {
246             return false;
247         }
248         PrintDocumentInfo other = (PrintDocumentInfo) obj;
249         if (!TextUtils.equals(mName, other.mName)) {
250             return false;
251         }
252         if (mContentType != other.mContentType) {
253             return false;
254         }
255         if (mPageCount != other.mPageCount) {
256             return false;
257         }
258         if (mDataSize != other.mDataSize) {
259             return false;
260         }
261         return true;
262     }
263 
264     @Override
toString()265     public String toString() {
266         StringBuilder builder = new StringBuilder();
267         builder.append("PrintDocumentInfo{");
268         builder.append("name=").append(mName);
269         builder.append(", pageCount=").append(mPageCount);
270         builder.append(", contentType=").append(contentTypeToString(mContentType));
271         builder.append(", dataSize=").append(mDataSize);
272         builder.append("}");
273         return builder.toString();
274     }
275 
contentTypeToString(int contentType)276     private String contentTypeToString(int contentType) {
277         switch (contentType) {
278             case CONTENT_TYPE_DOCUMENT: {
279                 return "CONTENT_TYPE_DOCUMENT";
280             }
281             case CONTENT_TYPE_PHOTO: {
282                 return "CONTENT_TYPE_PHOTO";
283             }
284             default: {
285                 return "CONTENT_TYPE_UNKNOWN";
286             }
287         }
288     }
289 
290     /**
291      * Builder for creating a {@link PrintDocumentInfo}.
292      */
293     public static final class Builder {
294         private final PrintDocumentInfo mPrototype;
295 
296         /**
297          * Constructor.
298          *
299          * <p>
300          * The values of the relevant properties are initialized with defaults.
301          * Please refer to the documentation of the individual setters for
302          * information about the default values.
303          * </p>
304          *
305          * @param name The document name which may be shown to the user and
306          * is the file name if the content it describes is saved as a PDF.
307          * Cannot be empty.
308          */
Builder(@onNull String name)309         public Builder(@NonNull String name) {
310             if (TextUtils.isEmpty(name)) {
311                 throw new IllegalArgumentException("name cannot be empty");
312             }
313             mPrototype = new PrintDocumentInfo();
314             mPrototype.mName = name;
315         }
316 
317         /**
318          * Sets the total number of pages.
319          * <p>
320          * <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
321          * </p>
322          *
323          * @param pageCount The number of pages. Must be greater than or equal to zero or
324          *            {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
325          * @return This builder.
326          */
setPageCount(@ntRangefrom = -1) int pageCount)327         public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
328             if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
329                 throw new IllegalArgumentException("pageCount"
330                         + " must be greater than or equal to zero or"
331                         + " DocumentInfo#PAGE_COUNT_UNKNOWN");
332             }
333             mPrototype.mPageCount = pageCount;
334             return this;
335         }
336 
337         /**
338          * Sets the content type.
339          * <p>
340          * <strong>Default: </strong> {@link #CONTENT_TYPE_DOCUMENT}
341          * </p>
342          *
343          * @param type The content type.
344          * @return This builder.
345          * @see #CONTENT_TYPE_UNKNOWN
346          * @see #CONTENT_TYPE_DOCUMENT
347          * @see #CONTENT_TYPE_PHOTO
348          */
setContentType(@ontentType int type)349         public @NonNull Builder setContentType(@ContentType int type) {
350             mPrototype.mContentType = type;
351             return this;
352         }
353 
354         /**
355          * Creates a new {@link PrintDocumentInfo} instance.
356          *
357          * @return The new instance.
358          */
build()359         public @NonNull PrintDocumentInfo build() {
360             // Zero pages is the same as unknown as in this case
361             // we will have to ask for all pages and look a the
362             // wiritten PDF file for the page count.
363             if (mPrototype.mPageCount == 0) {
364                 mPrototype.mPageCount = PAGE_COUNT_UNKNOWN;
365             }
366             return new PrintDocumentInfo(mPrototype);
367         }
368     }
369 
370     public static final Parcelable.Creator<PrintDocumentInfo> CREATOR =
371             new Creator<PrintDocumentInfo>() {
372         @Override
373         public PrintDocumentInfo createFromParcel(Parcel parcel) {
374             return new PrintDocumentInfo(parcel);
375         }
376 
377         @Override
378         public PrintDocumentInfo[] newArray(int size) {
379             return new PrintDocumentInfo[size];
380         }
381     };
382 }
383