1b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin/* 2b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Copyright (C) 2013 The Android Open Source Project 3b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 4b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 5b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * you may not use this file except in compliance with the License. 6b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * You may obtain a copy of the License at 7b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 8b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 9b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 10b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Unless required by applicable law or agreed to in writing, software 11b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 12b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * See the License for the specific language governing permissions and 14b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * limitations under the License. 15b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 16b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 17b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkinpackage android.util; 18b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 195b836f29a3f56f9d13b6004417330c41ec0c18aeJeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull; 205b836f29a3f56f9d13b6004417330c41ec0c18aeJeff Sharkey 21b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin/** 22b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Immutable class for describing width and height dimensions in pixels. 23b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 245ef33984d0cc50bf4654b0d8e9557ac34d44fdddJeff Sharkeypublic final class Size { 25b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 26b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Create a new immutable Size instance. 27b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 28b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @param width The width of the size, in pixels 29b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @param height The height of the size, in pixels 30b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 31b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public Size(int width, int height) { 32b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin mWidth = width; 33b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin mHeight = height; 34b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 35b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 36b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 37b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Get the width of the size (in pixels). 38b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @return width 39b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 40b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public int getWidth() { 41b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return mWidth; 42b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 43b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 44b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 45b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Get the height of the size (in pixels). 46b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @return height 47b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 48b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public int getHeight() { 49b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return mHeight; 50b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 51b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 52b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 53b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Check if this size is equal to another size. 54b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * <p> 55b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Two sizes are equal if and only if both their widths and heights are 56b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * equal. 57b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * </p> 58b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * <p> 59b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * A size object is never equal to any other type of object. 60b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * </p> 61b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 62b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @return {@code true} if the objects were equal, {@code false} otherwise 63b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 64b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin @Override 65b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public boolean equals(final Object obj) { 66b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin if (obj == null) { 67b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return false; 68b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 69b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin if (this == obj) { 70b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return true; 71b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 72b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin if (obj instanceof Size) { 73b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin Size other = (Size) obj; 74b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return mWidth == other.mWidth && mHeight == other.mHeight; 75b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 76b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return false; 77b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 78b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 79b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 80b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Return the size represented as a string with the format {@code "WxH"} 81b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * 82b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @return string representation of the size 83b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 84b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin @Override 85b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public String toString() { 86b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return mWidth + "x" + mHeight; 87b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 88b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 89b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar private static NumberFormatException invalidSize(String s) { 90b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw new NumberFormatException("Invalid Size: \"" + s + "\""); 91b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 92b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 93b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar /** 94b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Parses the specified string as a size value. 95b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p> 96b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * The ASCII characters {@code \}{@code u002a} ('*') and 97b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * {@code \}{@code u0078} ('x') are recognized as separators between 98b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * the width and height.</p> 99b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p> 100b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * For any {@code Size s}: {@code Size.parseSize(s.toString()).equals(s)}. 101b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * However, the method also handles sizes expressed in the 102b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * following forms:</p> 103b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p> 104b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * "<i>width</i>{@code x}<i>height</i>" or 105b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * "<i>width</i>{@code *}<i>height</i>" {@code => new Size(width, height)}, 106b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * where <i>width</i> and <i>height</i> are string integers potentially 107b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * containing a sign, such as "-10", "+7" or "5".</p> 108b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 109b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <pre>{@code 110b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Size.parseSize("3*+6").equals(new Size(3, 6)) == true 111b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Size.parseSize("-3x-6").equals(new Size(-3, -6)) == true 112b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Size.parseSize("4 by 3") => throws NumberFormatException 113b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * }</pre> 114b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 115b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @param string the string representation of a size value. 116b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @return the size value represented by {@code string}. 117b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 118b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @throws NumberFormatException if {@code string} cannot be parsed 119b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * as a size value. 120b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @throws NullPointerException if {@code string} was {@code null} 121b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar */ 122b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar public static Size parseSize(String string) 123b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throws NumberFormatException { 124b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar checkNotNull(string, "string must not be null"); 125b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 126b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar int sep_ix = string.indexOf('*'); 127b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar if (sep_ix < 0) { 128b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar sep_ix = string.indexOf('x'); 129b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 130b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar if (sep_ix < 0) { 131b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw invalidSize(string); 132b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 133b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar try { 134b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar return new Size(Integer.parseInt(string.substring(0, sep_ix)), 135b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar Integer.parseInt(string.substring(sep_ix + 1))); 136b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } catch (NumberFormatException e) { 137b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw invalidSize(string); 138b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 139b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 140b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 141b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin /** 142b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * {@inheritDoc} 143b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */ 144b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin @Override 145b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin public int hashCode() { 146b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin // assuming most sizes are <2^16, doing a rotate will give us perfect hashing 147b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); 148b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin } 149b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin 150b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin private final int mWidth; 151b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin private final int mHeight; 1525b836f29a3f56f9d13b6004417330c41ec0c18aeJeff Sharkey} 153