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.FloatRange;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.StringRes;
25 import android.annotation.TestApi;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.service.print.PrintJobInfoProto;
32 
33 import com.android.internal.util.Preconditions;
34 
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.util.Arrays;
38 
39 /**
40  * This class represents the description of a print job. The print job
41  * state includes properties such as its id, print attributes used for
42  * generating the content, and so on. Note that the print jobs state may
43  * change over time and this class represents a snapshot of this state.
44  */
45 public final class PrintJobInfo implements Parcelable {
46 
47     /** @hide */
48     @IntDef(prefix = { "STATE_" }, value = {
49             STATE_CREATED,
50             STATE_QUEUED,
51             STATE_STARTED,
52             STATE_BLOCKED,
53             STATE_COMPLETED,
54             STATE_FAILED,
55             STATE_CANCELED
56     })
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface State {
59     }
60 
61     /**
62      * Constant for matching any print job state.
63      *
64      * @hide
65      */
66     public static final int STATE_ANY = -1;
67 
68     /**
69      * Constant for matching any print job state.
70      *
71      * @hide
72      */
73     public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
74 
75     /**
76      * Constant for matching any active print job state.
77      *
78      * @hide
79      */
80     public static final int STATE_ANY_ACTIVE = -3;
81 
82     /**
83      * Constant for matching any scheduled, i.e. delivered to a print
84      * service, print job state.
85      *
86      * @hide
87      */
88     public static final int STATE_ANY_SCHEDULED = -4;
89 
90     /**
91      * Print job state: The print job is being created but not yet
92      * ready to be printed.
93      * <p>
94      * Next valid states: {@link #STATE_QUEUED}
95      * </p>
96      */
97     public static final int STATE_CREATED = PrintJobInfoProto.STATE_CREATED;
98 
99     /**
100      * Print job state: The print jobs is created, it is ready
101      * to be printed and should be processed.
102      * <p>
103      * Next valid states: {@link #STATE_STARTED}, {@link #STATE_FAILED},
104      * {@link #STATE_CANCELED}
105      * </p>
106      */
107     public static final int STATE_QUEUED = PrintJobInfoProto.STATE_QUEUED;
108 
109     /**
110      * Print job state: The print job is being printed.
111      * <p>
112      * Next valid states: {@link #STATE_COMPLETED}, {@link #STATE_FAILED},
113      * {@link #STATE_CANCELED}, {@link #STATE_BLOCKED}
114      * </p>
115      */
116     public static final int STATE_STARTED = PrintJobInfoProto.STATE_STARTED;
117 
118     /**
119      * Print job state: The print job is blocked.
120      * <p>
121      * Next valid states: {@link #STATE_FAILED}, {@link #STATE_CANCELED},
122      * {@link #STATE_STARTED}
123      * </p>
124      */
125     public static final int STATE_BLOCKED = PrintJobInfoProto.STATE_BLOCKED;
126 
127     /**
128      * Print job state: The print job is successfully printed.
129      * This is a terminal state.
130      * <p>
131      * Next valid states: None
132      * </p>
133      */
134     public static final int STATE_COMPLETED = PrintJobInfoProto.STATE_COMPLETED;
135 
136     /**
137      * Print job state: The print job was printing but printing failed.
138      * <p>
139      * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
140      * </p>
141      */
142     public static final int STATE_FAILED = PrintJobInfoProto.STATE_FAILED;
143 
144     /**
145      * Print job state: The print job is canceled.
146      * This is a terminal state.
147      * <p>
148      * Next valid states: None
149      * </p>
150      */
151     public static final int STATE_CANCELED = PrintJobInfoProto.STATE_CANCELED;
152 
153     /** The unique print job id. */
154     private PrintJobId mId;
155 
156     /** The human readable print job label. */
157     private String mLabel;
158 
159     /** The unique id of the printer. */
160     private PrinterId mPrinterId;
161 
162     /** The name of the printer - internally used */
163     private String mPrinterName;
164 
165     /** The state of the print job. */
166     private int mState;
167 
168     /** The id of the app that created the job. */
169     private int mAppId;
170 
171     /** Optional tag assigned by a print service.*/
172     private String mTag;
173 
174     /** The wall time when the print job was created. */
175     private long mCreationTime;
176 
177     /** How many copies to print. */
178     private int mCopies;
179 
180     /** The pages to print */
181     private PageRange[] mPageRanges;
182 
183     /** The print job attributes size. */
184     private PrintAttributes mAttributes;
185 
186     /** Information about the printed document. */
187     private PrintDocumentInfo mDocumentInfo;
188 
189     /** The progress made on printing this job or -1 if not set. */
190     private float mProgress;
191 
192     /** A short string describing the status of this job. */
193     private @Nullable CharSequence mStatus;
194 
195     /** A string resource describing the status of this job. */
196     private @StringRes int mStatusRes;
197     private @Nullable CharSequence mStatusResAppPackageName;
198 
199     /** Advanced printer specific options. */
200     private Bundle mAdvancedOptions;
201 
202     /** Whether we are trying to cancel this print job. */
203     private boolean mCanceling;
204 
205     /** @hide*/
PrintJobInfo()206     public PrintJobInfo() {
207         mProgress = -1;
208     }
209 
210     /** @hide */
PrintJobInfo(PrintJobInfo other)211     public PrintJobInfo(PrintJobInfo other) {
212         mId = other.mId;
213         mLabel = other.mLabel;
214         mPrinterId = other.mPrinterId;
215         mPrinterName = other.mPrinterName;
216         mState = other.mState;
217         mAppId = other.mAppId;
218         mTag = other.mTag;
219         mCreationTime = other.mCreationTime;
220         mCopies = other.mCopies;
221         mPageRanges = other.mPageRanges;
222         mAttributes = other.mAttributes;
223         mDocumentInfo = other.mDocumentInfo;
224         mProgress = other.mProgress;
225         mStatus = other.mStatus;
226         mStatusRes = other.mStatusRes;
227         mStatusResAppPackageName = other.mStatusResAppPackageName;
228         mCanceling = other.mCanceling;
229         mAdvancedOptions = other.mAdvancedOptions;
230     }
231 
PrintJobInfo(@onNull Parcel parcel)232     private PrintJobInfo(@NonNull Parcel parcel) {
233         mId = parcel.readParcelable(null);
234         mLabel = parcel.readString();
235         mPrinterId = parcel.readParcelable(null);
236         mPrinterName = parcel.readString();
237         mState = parcel.readInt();
238         mAppId = parcel.readInt();
239         mTag = parcel.readString();
240         mCreationTime = parcel.readLong();
241         mCopies = parcel.readInt();
242         Parcelable[] parcelables = parcel.readParcelableArray(null);
243         if (parcelables != null) {
244             mPageRanges = new PageRange[parcelables.length];
245             for (int i = 0; i < parcelables.length; i++) {
246                 mPageRanges[i] = (PageRange) parcelables[i];
247             }
248         }
249         mAttributes = (PrintAttributes) parcel.readParcelable(null);
250         mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
251         mProgress = parcel.readFloat();
252         mStatus = parcel.readCharSequence();
253         mStatusRes = parcel.readInt();
254         mStatusResAppPackageName = parcel.readCharSequence();
255         mCanceling = (parcel.readInt() == 1);
256         mAdvancedOptions = parcel.readBundle();
257 
258         if (mAdvancedOptions != null) {
259             Preconditions.checkArgument(!mAdvancedOptions.containsKey(null));
260         }
261     }
262 
263     /**
264      * Gets the unique print job id.
265      *
266      * @return The id.
267      */
getId()268     public @Nullable PrintJobId getId() {
269         return mId;
270     }
271 
272     /**
273      * Sets the unique print job id.
274      *
275      * @param id The job id.
276      *
277      * @hide
278      */
setId(@onNull PrintJobId id)279     public void setId(@NonNull PrintJobId id) {
280         this.mId = id;
281     }
282 
283     /**
284      * Gets the human readable job label.
285      *
286      * @return The label.
287      */
getLabel()288     public @NonNull String getLabel() {
289         return mLabel;
290     }
291 
292     /**
293      * Sets the human readable job label.
294      *
295      * @param label The label.
296      *
297      * @hide
298      */
setLabel(@onNull String label)299     public void setLabel(@NonNull String label) {
300         mLabel = label;
301     }
302 
303     /**
304      * Gets the unique target printer id.
305      *
306      * @return The target printer id.
307      */
getPrinterId()308     public @Nullable PrinterId getPrinterId() {
309         return mPrinterId;
310     }
311 
312     /**
313      * Sets the unique target printer id.
314      *
315      * @param printerId The target printer id.
316      *
317      * @hide
318      */
setPrinterId(@onNull PrinterId printerId)319     public void setPrinterId(@NonNull PrinterId printerId) {
320         mPrinterId = printerId;
321     }
322 
323     /**
324      * Gets the name of the target printer.
325      *
326      * @return The printer name.
327      *
328      * @hide
329      */
getPrinterName()330     public @Nullable String getPrinterName() {
331         return mPrinterName;
332     }
333 
334     /**
335      * Sets the name of the target printer.
336      *
337      * @param printerName The printer name.
338      *
339      * @hide
340      */
setPrinterName(@onNull String printerName)341     public void setPrinterName(@NonNull String printerName) {
342         mPrinterName = printerName;
343     }
344 
345     /**
346      * Gets the current job state.
347      *
348      * @return The job state.
349      *
350      * @see #STATE_CREATED
351      * @see #STATE_QUEUED
352      * @see #STATE_STARTED
353      * @see #STATE_COMPLETED
354      * @see #STATE_BLOCKED
355      * @see #STATE_FAILED
356      * @see #STATE_CANCELED
357      */
getState()358     public @State int getState() {
359         return mState;
360     }
361 
362     /**
363      * Sets the current job state.
364      *
365      * @param state The job state.
366      *
367      * @hide
368      */
setState(int state)369     public void setState(int state) {
370         mState = state;
371     }
372 
373     /**
374      * Sets the progress of the print job.
375      *
376      * @param progress the progress of the job
377      *
378      * @hide
379      */
setProgress(@loatRangefrom=0.0, to=1.0) float progress)380     public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
381         Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
382 
383         mProgress = progress;
384     }
385 
386     /**
387      * Sets the status of the print job.
388      *
389      * @param status the status of the job, can be null
390      *
391      * @hide
392      */
setStatus(@ullable CharSequence status)393     public void setStatus(@Nullable CharSequence status) {
394         mStatusRes = 0;
395         mStatusResAppPackageName = null;
396 
397         mStatus = status;
398     }
399 
400     /**
401      * Sets the status of the print job.
402      *
403      * @param status The new status as a string resource
404      * @param appPackageName App package name the resource belongs to
405      *
406      * @hide
407      */
setStatus(@tringRes int status, @NonNull CharSequence appPackageName)408     public void setStatus(@StringRes int status, @NonNull CharSequence appPackageName) {
409         mStatus = null;
410 
411         mStatusRes = status;
412         mStatusResAppPackageName = appPackageName;
413     }
414 
415     /**
416      * Sets the owning application id.
417      *
418      * @return The owning app id.
419      *
420      * @hide
421      */
getAppId()422     public int getAppId() {
423         return mAppId;
424     }
425 
426     /**
427      * Sets the owning application id.
428      *
429      * @param appId The owning app id.
430      *
431      * @hide
432      */
setAppId(int appId)433     public void setAppId(int appId) {
434         mAppId = appId;
435     }
436 
437     /**
438      * Gets the optional tag assigned by a print service.
439      *
440      * @return The tag.
441      *
442      * @hide
443      */
getTag()444     public String getTag() {
445         return mTag;
446     }
447 
448     /**
449      * Sets the optional tag assigned by a print service.
450      *
451      * @param tag The tag.
452      *
453      * @hide
454      */
setTag(String tag)455     public void setTag(String tag) {
456         mTag = tag;
457     }
458 
459     /**
460      * Gets the wall time in millisecond when this print job was created.
461      *
462      * @return The creation time in milliseconds.
463      */
getCreationTime()464     public long getCreationTime() {
465         return mCreationTime;
466     }
467 
468     /**
469      * Sets the wall time in milliseconds when this print job was created.
470      *
471      * @param creationTime The creation time in milliseconds.
472      *
473      * @hide
474      */
setCreationTime(long creationTime)475     public void setCreationTime(long creationTime) {
476         if (creationTime < 0) {
477             throw new IllegalArgumentException("creationTime must be non-negative.");
478         }
479         mCreationTime = creationTime;
480     }
481 
482     /**
483      * Gets the number of copies.
484      *
485      * @return The number of copies or zero if not set.
486      */
getCopies()487     public @IntRange(from = 0) int getCopies() {
488         return mCopies;
489     }
490 
491     /**
492      * Sets the number of copies.
493      *
494      * @param copyCount The number of copies.
495      *
496      * @hide
497      */
setCopies(int copyCount)498     public void setCopies(int copyCount) {
499         if (copyCount < 1) {
500             throw new IllegalArgumentException("Copies must be more than one.");
501         }
502         mCopies = copyCount;
503     }
504 
505     /**
506      * Gets the included pages.
507      *
508      * @return The included pages or <code>null</code> if not set.
509      */
getPages()510     public @Nullable PageRange[] getPages() {
511         return mPageRanges;
512     }
513 
514     /**
515      * Sets the included pages.
516      *
517      * @param pageRanges The included pages.
518      *
519      * @hide
520      */
setPages(PageRange[] pageRanges)521     public void setPages(PageRange[] pageRanges) {
522         mPageRanges = pageRanges;
523     }
524 
525     /**
526      * Gets the print job attributes.
527      *
528      * @return The attributes.
529      */
getAttributes()530     public @NonNull PrintAttributes getAttributes() {
531         return mAttributes;
532     }
533 
534     /**
535      * Sets the print job attributes.
536      *
537      * @param attributes The attributes.
538      *
539      * @hide
540      */
setAttributes(PrintAttributes attributes)541     public void setAttributes(PrintAttributes attributes) {
542         mAttributes = attributes;
543     }
544 
545     /**
546      * Gets the info describing the printed document.
547      *
548      * @return The document info.
549      *
550      * @hide
551      */
getDocumentInfo()552     public PrintDocumentInfo getDocumentInfo() {
553         return mDocumentInfo;
554     }
555 
556     /**
557      * Sets the info describing the printed document.
558      *
559      * @param info The document info.
560      *
561      * @hide
562      */
setDocumentInfo(PrintDocumentInfo info)563     public void setDocumentInfo(PrintDocumentInfo info) {
564         mDocumentInfo = info;
565     }
566 
567     /**
568      * Gets whether this print is being cancelled.
569      *
570      * @return True if the print job is being cancelled.
571      *
572      * @hide
573      */
isCancelling()574     public boolean isCancelling() {
575         return mCanceling;
576     }
577 
578     /**
579      * Sets whether this print is being cancelled.
580      *
581      * @param cancelling True if the print job is being cancelled.
582      *
583      * @hide
584      */
setCancelling(boolean cancelling)585     public void setCancelling(boolean cancelling) {
586         mCanceling = cancelling;
587     }
588 
589     /**
590      * Gets whether this job has a given advanced (printer specific) print
591      * option.
592      *
593      * @param key The option key.
594      * @return Whether the option is present.
595      */
hasAdvancedOption(String key)596     public boolean hasAdvancedOption(String key) {
597         return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
598     }
599 
600     /**
601      * Gets the value of an advanced (printer specific) print option.
602      *
603      * @param key The option key.
604      * @return The option value.
605      */
getAdvancedStringOption(String key)606     public String getAdvancedStringOption(String key) {
607         if (mAdvancedOptions != null) {
608             return mAdvancedOptions.getString(key);
609         }
610         return null;
611     }
612 
613     /**
614      * Gets the value of an advanced (printer specific) print option.
615      *
616      * @param key The option key.
617      * @return The option value.
618      */
getAdvancedIntOption(String key)619     public int getAdvancedIntOption(String key) {
620         if (mAdvancedOptions != null) {
621             return mAdvancedOptions.getInt(key);
622         }
623         return 0;
624     }
625 
626     /**
627      * Gets the advanced options.
628      *
629      * @return The advanced options.
630      *
631      * @hide
632      */
getAdvancedOptions()633     public Bundle getAdvancedOptions() {
634         return mAdvancedOptions;
635     }
636 
637     /**
638      * Sets the advanced options.
639      *
640      * @param options The advanced options.
641      *
642      * @hide
643      */
setAdvancedOptions(Bundle options)644     public void setAdvancedOptions(Bundle options) {
645         mAdvancedOptions = options;
646     }
647 
648     @Override
describeContents()649     public int describeContents() {
650         return 0;
651     }
652 
653     @Override
writeToParcel(Parcel parcel, int flags)654     public void writeToParcel(Parcel parcel, int flags) {
655         parcel.writeParcelable(mId, flags);
656         parcel.writeString(mLabel);
657         parcel.writeParcelable(mPrinterId, flags);
658         parcel.writeString(mPrinterName);
659         parcel.writeInt(mState);
660         parcel.writeInt(mAppId);
661         parcel.writeString(mTag);
662         parcel.writeLong(mCreationTime);
663         parcel.writeInt(mCopies);
664         parcel.writeParcelableArray(mPageRanges, flags);
665         parcel.writeParcelable(mAttributes, flags);
666         parcel.writeParcelable(mDocumentInfo, 0);
667         parcel.writeFloat(mProgress);
668         parcel.writeCharSequence(mStatus);
669         parcel.writeInt(mStatusRes);
670         parcel.writeCharSequence(mStatusResAppPackageName);
671         parcel.writeInt(mCanceling ? 1 : 0);
672         parcel.writeBundle(mAdvancedOptions);
673     }
674 
675     @Override
toString()676     public String toString() {
677         StringBuilder builder = new StringBuilder();
678         builder.append("PrintJobInfo{");
679         builder.append("label: ").append(mLabel);
680         builder.append(", id: ").append(mId);
681         builder.append(", state: ").append(stateToString(mState));
682         builder.append(", printer: " + mPrinterId);
683         builder.append(", tag: ").append(mTag);
684         builder.append(", creationTime: " + mCreationTime);
685         builder.append(", copies: ").append(mCopies);
686         builder.append(", attributes: " + (mAttributes != null
687                 ? mAttributes.toString() : null));
688         builder.append(", documentInfo: " + (mDocumentInfo != null
689                 ? mDocumentInfo.toString() : null));
690         builder.append(", cancelling: " + mCanceling);
691         builder.append(", pages: " + (mPageRanges != null
692                 ? Arrays.toString(mPageRanges) : null));
693         builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null));
694         builder.append(", progress: " + mProgress);
695         builder.append(", status: " + (mStatus != null
696                 ? mStatus.toString() : null));
697         builder.append(", statusRes: " + mStatusRes);
698         builder.append(", statusResAppPackageName: " + (mStatusResAppPackageName != null
699                 ? mStatusResAppPackageName.toString() : null));
700         builder.append("}");
701         return builder.toString();
702     }
703 
704     /** @hide */
stateToString(int state)705     public static String stateToString(int state) {
706         switch (state) {
707             case STATE_CREATED: {
708                 return "STATE_CREATED";
709             }
710             case STATE_QUEUED: {
711                 return "STATE_QUEUED";
712             }
713             case STATE_STARTED: {
714                 return "STATE_STARTED";
715             }
716             case STATE_BLOCKED: {
717                 return "STATE_BLOCKED";
718             }
719             case STATE_FAILED: {
720                 return "STATE_FAILED";
721             }
722             case STATE_COMPLETED: {
723                 return "STATE_COMPLETED";
724             }
725             case STATE_CANCELED: {
726                 return "STATE_CANCELED";
727             }
728             default: {
729                 return "STATE_UNKNOWN";
730             }
731         }
732     }
733 
734     /**
735      * Get the progress that has been made printing this job.
736      *
737      * @return the print progress or -1 if not set
738      * @hide
739      */
740     @TestApi
getProgress()741     public float getProgress() {
742         return mProgress;
743     }
744 
745     /**
746      * Get the status of this job.
747      *
748      * @param pm Package manager used to resolve the string
749      *
750      * @return the status of this job or null if not set
751      * @hide
752      */
753     @TestApi
getStatus(@onNull PackageManager pm)754     public @Nullable CharSequence getStatus(@NonNull PackageManager pm) {
755         if (mStatusRes == 0) {
756             return mStatus;
757         } else {
758             try {
759                 return pm.getResourcesForApplication(mStatusResAppPackageName.toString())
760                         .getString(mStatusRes);
761             } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
762                 return null;
763             }
764         }
765     }
766 
767     /**
768      * Builder for creating a {@link PrintJobInfo}.
769      */
770     public static final class Builder {
771         private final PrintJobInfo mPrototype;
772 
773         /**
774          * Constructor.
775          *
776          * @param prototype Prototype to use as a starting point.
777          * Can be <code>null</code>.
778          */
Builder(@ullable PrintJobInfo prototype)779         public Builder(@Nullable PrintJobInfo prototype) {
780             mPrototype = (prototype != null)
781                     ? new PrintJobInfo(prototype)
782                     : new PrintJobInfo();
783         }
784 
785         /**
786          * Sets the number of copies.
787          *
788          * @param copies The number of copies.
789          */
setCopies(@ntRangefrom = 1) int copies)790         public void setCopies(@IntRange(from = 1) int copies) {
791             mPrototype.mCopies = copies;
792         }
793 
794         /**
795          * Sets the print job attributes.
796          *
797          * @param attributes The attributes.
798          */
setAttributes(@onNull PrintAttributes attributes)799         public void setAttributes(@NonNull PrintAttributes attributes) {
800             mPrototype.mAttributes = attributes;
801         }
802 
803         /**
804          * Sets the included pages.
805          *
806          * @param pages The included pages.
807          */
setPages(@onNull PageRange[] pages)808         public void setPages(@NonNull PageRange[] pages) {
809             mPrototype.mPageRanges = pages;
810         }
811 
812         /**
813          * Sets the progress of the print job.
814          *
815          * @param progress the progress of the job
816          * @hide
817          */
setProgress(@loatRangefrom=0.0, to=1.0) float progress)818         public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
819             Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
820 
821             mPrototype.mProgress = progress;
822         }
823 
824         /**
825          * Sets the status of the print job.
826          *
827          * @param status the status of the job, can be null
828          * @hide
829          */
setStatus(@ullable CharSequence status)830         public void setStatus(@Nullable CharSequence status) {
831             mPrototype.mStatus = status;
832         }
833 
834         /**
835          * Puts an advanced (printer specific) option.
836          *
837          * @param key The option key.
838          * @param value The option value.
839          */
putAdvancedOption(@onNull String key, @Nullable String value)840         public void putAdvancedOption(@NonNull String key, @Nullable String value) {
841             Preconditions.checkNotNull(key, "key cannot be null");
842 
843             if (mPrototype.mAdvancedOptions == null) {
844                 mPrototype.mAdvancedOptions = new Bundle();
845             }
846             mPrototype.mAdvancedOptions.putString(key, value);
847         }
848 
849         /**
850          * Puts an advanced (printer specific) option.
851          *
852          * @param key The option key.
853          * @param value The option value.
854          */
putAdvancedOption(@onNull String key, int value)855         public void putAdvancedOption(@NonNull String key, int value) {
856             if (mPrototype.mAdvancedOptions == null) {
857                 mPrototype.mAdvancedOptions = new Bundle();
858             }
859             mPrototype.mAdvancedOptions.putInt(key, value);
860         }
861 
862         /**
863          * Creates a new {@link PrintJobInfo} instance.
864          *
865          * @return The new instance.
866          */
build()867         public @NonNull PrintJobInfo build() {
868             return mPrototype;
869         }
870     }
871 
872     public static final Parcelable.Creator<PrintJobInfo> CREATOR =
873             new Creator<PrintJobInfo>() {
874         @Override
875         public PrintJobInfo createFromParcel(Parcel parcel) {
876             return new PrintJobInfo(parcel);
877         }
878 
879         @Override
880         public PrintJobInfo[] newArray(int size) {
881             return new PrintJobInfo[size];
882         }
883     };
884 }
885