• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Parcel;
20 import android.os.Parcelable;
21 import android.print.PrintAttributes.Margins;
22 import android.print.PrintAttributes.MediaSize;
23 import android.print.PrintAttributes.Resolution;
24 
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29 
30 /**
31  * This class represents the capabilities of a printer. Instances
32  * of this class are created by a print service to report the
33  * capabilities of a printer it manages. The capabilities of a
34  * printer specify how it can print content. For example, what
35  * are the media sizes supported by the printer, what are the
36  * minimal margins of the printer based on its technical design,
37  * etc.
38  */
39 public final class PrinterCapabilitiesInfo implements Parcelable {
40     /**
41      * Undefined default value.
42      *
43      * @hide
44      */
45     public static final int DEFAULT_UNDEFINED = -1;
46 
47     private static final int PROPERTY_MEDIA_SIZE = 0;
48     private static final int PROPERTY_RESOLUTION = 1;
49     private static final int PROPERTY_COLOR_MODE = 2;
50     private static final int PROPERTY_COUNT = 3;
51 
52     private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
53 
54     private Margins mMinMargins = DEFAULT_MARGINS;
55     private List<MediaSize> mMediaSizes;
56     private List<Resolution> mResolutions;
57 
58     private int mColorModes;
59 
60     private final int[] mDefaults = new int[PROPERTY_COUNT];
61 
62     /**
63      * @hide
64      */
PrinterCapabilitiesInfo()65     public PrinterCapabilitiesInfo() {
66         Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
67     }
68 
69     /**
70      * @hide
71      */
PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype)72     public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
73         copyFrom(prototype);
74     }
75 
76     /**
77      * @hide
78      */
copyFrom(PrinterCapabilitiesInfo other)79     public void copyFrom(PrinterCapabilitiesInfo other) {
80         if (this == other) {
81             return;
82         }
83 
84         mMinMargins = other.mMinMargins;
85 
86         if (other.mMediaSizes != null) {
87             if (mMediaSizes != null) {
88                 mMediaSizes.clear();
89                 mMediaSizes.addAll(other.mMediaSizes);
90             } else {
91                 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
92             }
93         } else {
94             mMediaSizes = null;
95         }
96 
97         if (other.mResolutions != null) {
98             if (mResolutions != null) {
99                 mResolutions.clear();
100                 mResolutions.addAll(other.mResolutions);
101             } else {
102                 mResolutions = new ArrayList<Resolution>(other.mResolutions);
103             }
104         } else {
105             mResolutions = null;
106         }
107 
108         mColorModes = other.mColorModes;
109 
110         final int defaultCount = other.mDefaults.length;
111         for (int i = 0; i < defaultCount; i++) {
112             mDefaults[i] = other.mDefaults[i];
113         }
114     }
115 
116     /**
117      * Gets the supported media sizes.
118      *
119      * @return The media sizes.
120      */
getMediaSizes()121     public List<MediaSize> getMediaSizes() {
122         return Collections.unmodifiableList(mMediaSizes);
123     }
124 
125     /**
126      * Gets the supported resolutions.
127      *
128      * @return The resolutions.
129      */
getResolutions()130     public List<Resolution> getResolutions() {
131         return Collections.unmodifiableList(mResolutions);
132     }
133 
134     /**
135      * Gets the minimal margins. These are the minimal margins
136      * the printer physically supports.
137      *
138      * @return The minimal margins.
139      */
getMinMargins()140     public Margins getMinMargins() {
141         return mMinMargins;
142     }
143 
144     /**
145      * Gets the bit mask of supported color modes.
146      *
147      * @return The bit mask of supported color modes.
148      *
149      * @see PrintAttributes#COLOR_MODE_COLOR
150      * @see PrintAttributes#COLOR_MODE_MONOCHROME
151      */
getColorModes()152     public int getColorModes() {
153         return mColorModes;
154     }
155 
156     /**
157      * Gets the default print attributes.
158      *
159      * @return The default attributes.
160      */
getDefaults()161     public PrintAttributes getDefaults() {
162         PrintAttributes.Builder builder = new PrintAttributes.Builder();
163 
164         builder.setMinMargins(mMinMargins);
165 
166         final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
167         if (mediaSizeIndex >= 0) {
168             builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
169         }
170 
171         final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
172         if (resolutionIndex >= 0) {
173             builder.setResolution(mResolutions.get(resolutionIndex));
174         }
175 
176         final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
177         if (colorMode > 0) {
178             builder.setColorMode(colorMode);
179         }
180 
181         return builder.build();
182     }
183 
PrinterCapabilitiesInfo(Parcel parcel)184     private PrinterCapabilitiesInfo(Parcel parcel) {
185         mMinMargins = readMargins(parcel);
186         readMediaSizes(parcel);
187         readResolutions(parcel);
188 
189         mColorModes = parcel.readInt();
190 
191         readDefaults(parcel);
192     }
193 
194     @Override
describeContents()195     public int describeContents() {
196         return 0;
197     }
198 
199     @Override
writeToParcel(Parcel parcel, int flags)200     public void writeToParcel(Parcel parcel, int flags) {
201         writeMargins(mMinMargins, parcel);
202         writeMediaSizes(parcel);
203         writeResolutions(parcel);
204 
205         parcel.writeInt(mColorModes);
206 
207         writeDefaults(parcel);
208     }
209 
210     @Override
hashCode()211     public int hashCode() {
212         final int prime = 31;
213         int result = 1;
214         result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
215         result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
216         result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
217         result = prime * result + mColorModes;
218         result = prime * result + Arrays.hashCode(mDefaults);
219         return result;
220     }
221 
222     @Override
equals(Object obj)223     public boolean equals(Object obj) {
224         if (this == obj) {
225             return true;
226         }
227         if (obj == null) {
228             return false;
229         }
230         if (getClass() != obj.getClass()) {
231             return false;
232         }
233         PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
234         if (mMinMargins == null) {
235             if (other.mMinMargins != null) {
236                 return false;
237             }
238         } else if (!mMinMargins.equals(other.mMinMargins)) {
239             return false;
240         }
241         if (mMediaSizes == null) {
242             if (other.mMediaSizes != null) {
243                 return false;
244             }
245         } else if (!mMediaSizes.equals(other.mMediaSizes)) {
246             return false;
247         }
248         if (mResolutions == null) {
249             if (other.mResolutions != null) {
250                 return false;
251             }
252         } else if (!mResolutions.equals(other.mResolutions)) {
253             return false;
254         }
255         if (mColorModes != other.mColorModes) {
256             return false;
257         }
258         if (!Arrays.equals(mDefaults, other.mDefaults)) {
259             return false;
260         }
261         return true;
262     }
263 
264     @Override
toString()265     public String toString() {
266         StringBuilder builder = new StringBuilder();
267         builder.append("PrinterInfo{");
268         builder.append("minMargins=").append(mMinMargins);
269         builder.append(", mediaSizes=").append(mMediaSizes);
270         builder.append(", resolutions=").append(mResolutions);
271         builder.append(", colorModes=").append(colorModesToString());
272         builder.append("\"}");
273         return builder.toString();
274     }
275 
colorModesToString()276     private String colorModesToString() {
277         StringBuilder builder = new StringBuilder();
278         builder.append('[');
279         int colorModes = mColorModes;
280         while (colorModes != 0) {
281             final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
282             colorModes &= ~colorMode;
283             if (builder.length() > 1) {
284                 builder.append(", ");
285             }
286             builder.append(PrintAttributes.colorModeToString(colorMode));
287         }
288         builder.append(']');
289         return builder.toString();
290     }
291 
writeMediaSizes(Parcel parcel)292     private void writeMediaSizes(Parcel parcel) {
293         if (mMediaSizes == null) {
294             parcel.writeInt(0);
295             return;
296         }
297         final int mediaSizeCount = mMediaSizes.size();
298         parcel.writeInt(mediaSizeCount);
299         for (int i = 0; i < mediaSizeCount; i++) {
300             mMediaSizes.get(i).writeToParcel(parcel);
301         }
302     }
303 
readMediaSizes(Parcel parcel)304     private void readMediaSizes(Parcel parcel) {
305         final int mediaSizeCount = parcel.readInt();
306         if (mediaSizeCount > 0 && mMediaSizes == null) {
307             mMediaSizes = new ArrayList<MediaSize>();
308         }
309         for (int i = 0; i < mediaSizeCount; i++) {
310             mMediaSizes.add(MediaSize.createFromParcel(parcel));
311         }
312     }
313 
writeResolutions(Parcel parcel)314     private void writeResolutions(Parcel parcel) {
315         if (mResolutions == null) {
316             parcel.writeInt(0);
317             return;
318         }
319         final int resolutionCount = mResolutions.size();
320         parcel.writeInt(resolutionCount);
321         for (int i = 0; i < resolutionCount; i++) {
322             mResolutions.get(i).writeToParcel(parcel);
323         }
324     }
325 
readResolutions(Parcel parcel)326     private void readResolutions(Parcel parcel) {
327         final int resolutionCount = parcel.readInt();
328         if (resolutionCount > 0 && mResolutions == null) {
329             mResolutions = new ArrayList<Resolution>();
330         }
331         for (int i = 0; i < resolutionCount; i++) {
332             mResolutions.add(Resolution.createFromParcel(parcel));
333         }
334     }
335 
writeMargins(Margins margins, Parcel parcel)336     private void writeMargins(Margins margins, Parcel parcel) {
337         if (margins == null) {
338             parcel.writeInt(0);
339         } else {
340             parcel.writeInt(1);
341             margins.writeToParcel(parcel);
342         }
343     }
344 
readMargins(Parcel parcel)345     private Margins readMargins(Parcel parcel) {
346         return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
347     }
348 
readDefaults(Parcel parcel)349     private void readDefaults(Parcel parcel) {
350         final int defaultCount = parcel.readInt();
351         for (int i = 0; i < defaultCount; i++) {
352             mDefaults[i] = parcel.readInt();
353         }
354     }
355 
writeDefaults(Parcel parcel)356     private void writeDefaults(Parcel parcel) {
357         final int defaultCount = mDefaults.length;
358         parcel.writeInt(defaultCount);
359         for (int i = 0; i < defaultCount; i++) {
360             parcel.writeInt(mDefaults[i]);
361         }
362     }
363 
364     /**
365      * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
366      * responsible to enforce that all required attributes have at least one
367      * default value. In other words, this class creates only well-formed {@link
368      * PrinterCapabilitiesInfo}s.
369      * <p>
370      * Look at the individual methods for a reference whether a property is
371      * required or if it is optional.
372      * </p>
373      */
374     public static final class Builder {
375         private final PrinterCapabilitiesInfo mPrototype;
376 
377         /**
378          * Creates a new instance.
379          *
380          * @param printerId The printer id. Cannot be <code>null</code>.
381          *
382          * @throws IllegalArgumentException If the printer id is <code>null</code>.
383          */
Builder(PrinterId printerId)384         public Builder(PrinterId printerId) {
385             if (printerId == null) {
386                 throw new IllegalArgumentException("printerId cannot be null.");
387             }
388             mPrototype = new PrinterCapabilitiesInfo();
389         }
390 
391         /**
392          * Adds a supported media size.
393          * <p>
394          * <strong>Required:</strong> Yes
395          * </p>
396          *
397          * @param mediaSize A media size.
398          * @param isDefault Whether this is the default.
399          * @return This builder.
400          * @throws IllegalArgumentException If set as default and there
401          *     is already a default.
402          *
403          * @see PrintAttributes.MediaSize
404          */
addMediaSize(MediaSize mediaSize, boolean isDefault)405         public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
406             if (mPrototype.mMediaSizes == null) {
407                 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
408             }
409             final int insertionIndex = mPrototype.mMediaSizes.size();
410             mPrototype.mMediaSizes.add(mediaSize);
411             if (isDefault) {
412                 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
413                 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
414             }
415             return this;
416         }
417 
418         /**
419          * Adds a supported resolution.
420          * <p>
421          * <strong>Required:</strong> Yes
422          * </p>
423          *
424          * @param resolution A resolution.
425          * @param isDefault Whether this is the default.
426          * @return This builder.
427          *
428          * @throws IllegalArgumentException If set as default and there
429          *     is already a default.
430          *
431          * @see PrintAttributes.Resolution
432          */
addResolution(Resolution resolution, boolean isDefault)433         public Builder addResolution(Resolution resolution, boolean isDefault) {
434             if (mPrototype.mResolutions == null) {
435                 mPrototype.mResolutions = new ArrayList<Resolution>();
436             }
437             final int insertionIndex = mPrototype.mResolutions.size();
438             mPrototype.mResolutions.add(resolution);
439             if (isDefault) {
440                 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
441                 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
442             }
443             return this;
444         }
445 
446         /**
447          * Sets the minimal margins. These are the minimal margins
448          * the printer physically supports.
449          *
450          * <p>
451          * <strong>Required:</strong> Yes
452          * </p>
453          *
454          * @param margins The margins.
455          * @return This builder.
456          *
457          * @throws IllegalArgumentException If margins are <code>null</code>.
458          *
459          * @see PrintAttributes.Margins
460          */
setMinMargins(Margins margins)461         public Builder setMinMargins(Margins margins) {
462             if (margins == null) {
463                 throw new IllegalArgumentException("margins cannot be null");
464             }
465             mPrototype.mMinMargins = margins;
466             return this;
467         }
468 
469         /**
470          * Sets the color modes.
471          * <p>
472          * <strong>Required:</strong> Yes
473          * </p>
474          *
475          * @param colorModes The color mode bit mask.
476          * @param defaultColorMode The default color mode.
477          * @return This builder.
478          * <p>
479          * <strong>Note:</strong> On platform version 19 (Kitkat) specifying
480          * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler
481          * crash. Hence, you should declare either both color modes or
482          * PrintAttributes#COLOR_MODE_COLOR.
483          * </p>
484          *
485          * @throws IllegalArgumentException If color modes contains an invalid
486          *         mode bit or if the default color mode is invalid.
487          *
488          * @see PrintAttributes#COLOR_MODE_COLOR
489          * @see PrintAttributes#COLOR_MODE_MONOCHROME
490          */
setColorModes(int colorModes, int defaultColorMode)491         public Builder setColorModes(int colorModes, int defaultColorMode) {
492             int currentModes = colorModes;
493             while (currentModes > 0) {
494                 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
495                 currentModes &= ~currentMode;
496                 PrintAttributes.enforceValidColorMode(currentMode);
497             }
498             if ((colorModes & defaultColorMode) == 0) {
499                 throw new IllegalArgumentException("Default color mode not in color modes.");
500             }
501             PrintAttributes.enforceValidColorMode(colorModes);
502             mPrototype.mColorModes = colorModes;
503             mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
504             return this;
505         }
506 
507         /**
508          * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
509          * required properties have been specified. See individual methods
510          * in this class for reference about required attributes.
511          *
512          * @return A new {@link PrinterCapabilitiesInfo}.
513          *
514          * @throws IllegalStateException If a required attribute was not specified.
515          */
build()516         public PrinterCapabilitiesInfo build() {
517             if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
518                 throw new IllegalStateException("No media size specified.");
519             }
520             if (mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] == DEFAULT_UNDEFINED) {
521                 throw new IllegalStateException("No default media size specified.");
522             }
523             if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
524                 throw new IllegalStateException("No resolution specified.");
525             }
526             if (mPrototype.mDefaults[PROPERTY_RESOLUTION] == DEFAULT_UNDEFINED) {
527                 throw new IllegalStateException("No default resolution specified.");
528             }
529             if (mPrototype.mColorModes == 0) {
530                 throw new IllegalStateException("No color mode specified.");
531             }
532             if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
533                 throw new IllegalStateException("No default color mode specified.");
534             }
535             if (mPrototype.mMinMargins == null) {
536                 throw new IllegalArgumentException("margins cannot be null");
537             }
538             return mPrototype;
539         }
540 
throwIfDefaultAlreadySpecified(int propertyIndex)541         private void throwIfDefaultAlreadySpecified(int propertyIndex) {
542             if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
543                 throw new IllegalArgumentException("Default already specified.");
544             }
545         }
546     }
547 
548     public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
549             new Parcelable.Creator<PrinterCapabilitiesInfo>() {
550         @Override
551         public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
552             return new PrinterCapabilitiesInfo(parcel);
553         }
554 
555         @Override
556         public PrinterCapabilitiesInfo[] newArray(int size) {
557             return new PrinterCapabilitiesInfo[size];
558         }
559     };
560 }
561 
562