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