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