Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2014 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 import static com.android.internal.util.Preconditions.checkArgumentFinite;
     21 
     22 /**
     23  * Immutable class for describing width and height dimensions in some arbitrary
     24  * unit.
     25  * <p>
     26  * Width and height are finite values stored as a floating point representation.
     27  * </p>
     28  */
     29 public final class SizeF {
     30     /**
     31      * Create a new immutable SizeF instance.
     32      *
     33      * <p>Both the {@code width} and the {@code height} must be a finite number.
     34      * In particular, {@code NaN} and positive/negative infinity are illegal values.</p>
     35      *
     36      * @param width The width of the size
     37      * @param height The height of the size
     38      *
     39      * @throws IllegalArgumentException
     40      *             if either {@code width} or {@code height} was not finite.
     41      */
     42     public SizeF(final float width, final float height) {
     43         mWidth = checkArgumentFinite(width, "width");
     44         mHeight = checkArgumentFinite(height, "height");
     45     }
     46 
     47     /**
     48      * Get the width of the size (as an arbitrary unit).
     49      * @return width
     50      */
     51     public float getWidth() {
     52         return mWidth;
     53     }
     54 
     55     /**
     56      * Get the height of the size (as an arbitrary unit).
     57      * @return height
     58      */
     59     public float getHeight() {
     60         return mHeight;
     61     }
     62 
     63     /**
     64      * Check if this size is equal to another size.
     65      *
     66      * <p>Two sizes are equal if and only if both their widths and heights are the same.</p>
     67      *
     68      * <p>For this purpose, the width/height float values are considered to be the same if and only
     69      * if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value
     70      * when applied to each.</p>
     71      *
     72      * @return {@code true} if the objects were equal, {@code false} otherwise
     73      */
     74     @Override
     75     public boolean equals(final Object obj) {
     76         if (obj == null) {
     77             return false;
     78         }
     79         if (this == obj) {
     80             return true;
     81         }
     82         if (obj instanceof SizeF) {
     83             final SizeF other = (SizeF) obj;
     84             return mWidth == other.mWidth && mHeight == other.mHeight;
     85         }
     86         return false;
     87     }
     88 
     89     /**
     90      * Return the size represented as a string with the format {@code "WxH"}
     91      *
     92      * @return string representation of the size
     93      */
     94     @Override
     95     public String toString() {
     96         return mWidth + "x" + mHeight;
     97     }
     98 
     99     private static NumberFormatException invalidSizeF(String s) {
    100         throw new NumberFormatException("Invalid SizeF: \"" + s + "\"");
    101     }
    102 
    103     /**
    104      * Parses the specified string as a size value.
    105      * <p>
    106      * The ASCII characters {@code \}{@code u002a} ('*') and
    107      * {@code \}{@code u0078} ('x') are recognized as separators between
    108      * the width and height.</p>
    109      * <p>
    110      * For any {@code SizeF s}: {@code SizeF.parseSizeF(s.toString()).equals(s)}.
    111      * However, the method also handles sizes expressed in the
    112      * following forms:</p>
    113      * <p>
    114      * "<i>width</i>{@code x}<i>height</i>" or
    115      * "<i>width</i>{@code *}<i>height</i>" {@code => new SizeF(width, height)},
    116      * where <i>width</i> and <i>height</i> are string floats potentially
    117      * containing a sign, such as "-10.3", "+7" or "5.2", but not containing
    118      * an {@code 'x'} (such as a float in hexadecimal string format).</p>
    119      *
    120      * <pre>{@code
    121      * SizeF.parseSizeF("3.2*+6").equals(new SizeF(3.2f, 6.0f)) == true
    122      * SizeF.parseSizeF("-3x-6").equals(new SizeF(-3.0f, -6.0f)) == true
    123      * SizeF.parseSizeF("4 by 3") => throws NumberFormatException
    124      * }</pre>
    125      *
    126      * @param string the string representation of a size value.
    127      * @return the size value represented by {@code string}.
    128      *
    129      * @throws NumberFormatException if {@code string} cannot be parsed
    130      * as a size value.
    131      * @throws NullPointerException if {@code string} was {@code null}
    132      */
    133     public static SizeF parseSizeF(String string)
    134             throws NumberFormatException {
    135         checkNotNull(string, "string must not be null");
    136 
    137         int sep_ix = string.indexOf('*');
    138         if (sep_ix < 0) {
    139             sep_ix = string.indexOf('x');
    140         }
    141         if (sep_ix < 0) {
    142             throw invalidSizeF(string);
    143         }
    144         try {
    145             return new SizeF(Float.parseFloat(string.substring(0, sep_ix)),
    146                     Float.parseFloat(string.substring(sep_ix + 1)));
    147         } catch (NumberFormatException e) {
    148             throw invalidSizeF(string);
    149         } catch (IllegalArgumentException e) {
    150             throw invalidSizeF(string);
    151         }
    152     }
    153 
    154     /**
    155      * {@inheritDoc}
    156      */
    157     @Override
    158     public int hashCode() {
    159         return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
    160     }
    161 
    162     private final float mWidth;
    163     private final float mHeight;
    164 }
    165