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.print;
18
19import android.annotation.IntDef;
20import android.annotation.IntRange;
21import android.annotation.NonNull;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.text.TextUtils;
25import com.android.internal.util.Preconditions;
26
27import java.lang.annotation.Retention;
28import 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 */
77public 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     */
129    private PrintDocumentInfo() {
130        /* do nothing */
131    }
132
133    /**
134     * Creates a new instance.
135     *
136     * @param prototype from which to clone.
137     */
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     */
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     */
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     */
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     */
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     */
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     */
208    public void setDataSize(@IntRange(from = 0) long dataSize) {
209        mDataSize = dataSize;
210    }
211
212    @Override
213    public int describeContents() {
214        return 0;
215    }
216
217    @Override
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
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
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
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
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         */
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         */
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         */
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         */
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