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.util;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 /**
22  * Immutable class for describing width and height dimensions in pixels.
23  */
24 public final class Size {
25     /**
26      * Create a new immutable Size instance.
27      *
28      * @param width The width of the size, in pixels
29      * @param height The height of the size, in pixels
30      */
Size(int width, int height)31     public Size(int width, int height) {
32         mWidth = width;
33         mHeight = height;
34     }
35 
36     /**
37      * Get the width of the size (in pixels).
38      * @return width
39      */
getWidth()40     public int getWidth() {
41         return mWidth;
42     }
43 
44     /**
45      * Get the height of the size (in pixels).
46      * @return height
47      */
getHeight()48     public int getHeight() {
49         return mHeight;
50     }
51 
52     /**
53      * Check if this size is equal to another size.
54      * <p>
55      * Two sizes are equal if and only if both their widths and heights are
56      * equal.
57      * </p>
58      * <p>
59      * A size object is never equal to any other type of object.
60      * </p>
61      *
62      * @return {@code true} if the objects were equal, {@code false} otherwise
63      */
64     @Override
equals(final Object obj)65     public boolean equals(final Object obj) {
66         if (obj == null) {
67             return false;
68         }
69         if (this == obj) {
70             return true;
71         }
72         if (obj instanceof Size) {
73             Size other = (Size) obj;
74             return mWidth == other.mWidth && mHeight == other.mHeight;
75         }
76         return false;
77     }
78 
79     /**
80      * Return the size represented as a string with the format {@code "WxH"}
81      *
82      * @return string representation of the size
83      */
84     @Override
toString()85     public String toString() {
86         return mWidth + "x" + mHeight;
87     }
88 
invalidSize(String s)89     private static NumberFormatException invalidSize(String s) {
90         throw new NumberFormatException("Invalid Size: \"" + s + "\"");
91     }
92 
93     /**
94      * Parses the specified string as a size value.
95      * <p>
96      * The ASCII characters {@code \}{@code u002a} ('*') and
97      * {@code \}{@code u0078} ('x') are recognized as separators between
98      * the width and height.</p>
99      * <p>
100      * For any {@code Size s}: {@code Size.parseSize(s.toString()).equals(s)}.
101      * However, the method also handles sizes expressed in the
102      * following forms:</p>
103      * <p>
104      * "<i>width</i>{@code x}<i>height</i>" or
105      * "<i>width</i>{@code *}<i>height</i>" {@code => new Size(width, height)},
106      * where <i>width</i> and <i>height</i> are string integers potentially
107      * containing a sign, such as "-10", "+7" or "5".</p>
108      *
109      * <pre>{@code
110      * Size.parseSize("3*+6").equals(new Size(3, 6)) == true
111      * Size.parseSize("-3x-6").equals(new Size(-3, -6)) == true
112      * Size.parseSize("4 by 3") => throws NumberFormatException
113      * }</pre>
114      *
115      * @param string the string representation of a size value.
116      * @return the size value represented by {@code string}.
117      *
118      * @throws NumberFormatException if {@code string} cannot be parsed
119      * as a size value.
120      * @throws NullPointerException if {@code string} was {@code null}
121      */
parseSize(String string)122     public static Size parseSize(String string)
123             throws NumberFormatException {
124         checkNotNull(string, "string must not be null");
125 
126         int sep_ix = string.indexOf('*');
127         if (sep_ix < 0) {
128             sep_ix = string.indexOf('x');
129         }
130         if (sep_ix < 0) {
131             throw invalidSize(string);
132         }
133         try {
134             return new Size(Integer.parseInt(string.substring(0, sep_ix)),
135                     Integer.parseInt(string.substring(sep_ix + 1)));
136         } catch (NumberFormatException e) {
137             throw invalidSize(string);
138         }
139     }
140 
141     /**
142      * {@inheritDoc}
143      */
144     @Override
hashCode()145     public int hashCode() {
146         // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
147         return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
148     }
149 
150     private final int mWidth;
151     private final int mHeight;
152 }
153