|  | /* | 
|  | * Copyright (C) 2006 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | package android.graphics; | 
|  |  | 
|  | import android.annotation.CheckResult; | 
|  | import android.annotation.NonNull; | 
|  | import android.annotation.Nullable; | 
|  | import android.annotation.TestApi; | 
|  | import android.compat.annotation.UnsupportedAppUsage; | 
|  | import android.os.Parcel; | 
|  | import android.os.Parcelable; | 
|  | import android.text.TextUtils; | 
|  | import android.util.proto.ProtoInputStream; | 
|  | import android.util.proto.ProtoOutputStream; | 
|  | import android.util.proto.WireTypeMismatchException; | 
|  |  | 
|  | import java.io.IOException; | 
|  | import java.io.PrintWriter; | 
|  | import java.util.regex.Matcher; | 
|  | import java.util.regex.Pattern; | 
|  |  | 
|  | /** | 
|  | * Rect holds four integer coordinates for a rectangle. The rectangle is | 
|  | * represented by the coordinates of its 4 edges (left, top, right bottom). | 
|  | * These fields can be accessed directly. Use width() and height() to retrieve | 
|  | * the rectangle's width and height. Note: most methods do not check to see that | 
|  | * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). | 
|  | * <p> | 
|  | * Note that the right and bottom coordinates are exclusive. This means a Rect | 
|  | * being drawn untransformed onto a {@link android.graphics.Canvas} will draw | 
|  | * into the column and row described by its left and top coordinates, but not | 
|  | * those of its bottom and right. | 
|  | */ | 
|  | @android.ravenwood.annotation.RavenwoodKeepWholeClass | 
|  | public final class Rect implements Parcelable { | 
|  | public int left; | 
|  | public int top; | 
|  | public int right; | 
|  | public int bottom; | 
|  |  | 
|  | /** | 
|  | * A helper class for flattened rectange pattern recognition. A separate | 
|  | * class to avoid an initialization dependency on a regular expression | 
|  | * causing Rect to not be initializable with an ahead-of-time compilation | 
|  | * scheme. | 
|  | */ | 
|  | private static final class UnflattenHelper { | 
|  | private static final Pattern FLATTENED_PATTERN = Pattern.compile( | 
|  | "(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)"); | 
|  |  | 
|  | static Matcher getMatcher(String str) { | 
|  | return FLATTENED_PATTERN.matcher(str); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Create a new empty Rect. All coordinates are initialized to 0. | 
|  | */ | 
|  | public Rect() {} | 
|  |  | 
|  | /** | 
|  | * Create a new rectangle with the specified coordinates. Note: no range | 
|  | * checking is performed, so the caller must ensure that left <= right and | 
|  | * top <= bottom. | 
|  | * | 
|  | * @param left   The X coordinate of the left side of the rectangle | 
|  | * @param top    The Y coordinate of the top of the rectangle | 
|  | * @param right  The X coordinate of the right side of the rectangle | 
|  | * @param bottom The Y coordinate of the bottom of the rectangle | 
|  | */ | 
|  | public Rect(int left, int top, int right, int bottom) { | 
|  | this.left = left; | 
|  | this.top = top; | 
|  | this.right = right; | 
|  | this.bottom = bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Create a new rectangle, initialized with the values in the specified | 
|  | * rectangle (which is left unmodified). | 
|  | * | 
|  | * @param r The rectangle whose coordinates are copied into the new | 
|  | *          rectangle. | 
|  | */ | 
|  | public Rect(@Nullable Rect r) { | 
|  | if (r == null) { | 
|  | left = top = right = bottom = 0; | 
|  | } else { | 
|  | left = r.left; | 
|  | top = r.top; | 
|  | right = r.right; | 
|  | bottom = r.bottom; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public Rect(@Nullable Insets r) { | 
|  | if (r == null) { | 
|  | left = top = right = bottom = 0; | 
|  | } else { | 
|  | left = r.left; | 
|  | top = r.top; | 
|  | right = r.right; | 
|  | bottom = r.bottom; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a copy of {@code r} if {@code r} is not {@code null}, or {@code null} otherwise. | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | @Nullable | 
|  | public static Rect copyOrNull(@Nullable Rect r) { | 
|  | return r == null ? null : new Rect(r); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object o) { | 
|  | if (this == o) return true; | 
|  | if (o == null || getClass() != o.getClass()) return false; | 
|  |  | 
|  | Rect r = (Rect) o; | 
|  | return left == r.left && top == r.top && right == r.right && bottom == r.bottom; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | int result = left; | 
|  | result = 31 * result + top; | 
|  | result = 31 * result + right; | 
|  | result = 31 * result + bottom; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | StringBuilder sb = new StringBuilder(32); | 
|  | sb.append("Rect("); sb.append(left); sb.append(", "); | 
|  | sb.append(top); sb.append(" - "); sb.append(right); | 
|  | sb.append(", "); sb.append(bottom); sb.append(")"); | 
|  | return sb.toString(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return a string representation of the rectangle in a compact form. | 
|  | */ | 
|  | @NonNull | 
|  | public String toShortString() { | 
|  | return toShortString(new StringBuilder(32)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return a string representation of the rectangle in a compact form. | 
|  | * @hide | 
|  | */ | 
|  | @NonNull | 
|  | public String toShortString(@NonNull StringBuilder sb) { | 
|  | sb.setLength(0); | 
|  | sb.append('['); sb.append(left); sb.append(','); | 
|  | sb.append(top); sb.append("]["); sb.append(right); | 
|  | sb.append(','); sb.append(bottom); sb.append(']'); | 
|  | return sb.toString(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return a string representation of the rectangle in a well-defined format. | 
|  | * | 
|  | * <p>You can later recover the Rect from this string through | 
|  | * {@link #unflattenFromString(String)}. | 
|  | * | 
|  | * @return Returns a new String of the form "left top right bottom" | 
|  | */ | 
|  | @NonNull | 
|  | public String flattenToString() { | 
|  | StringBuilder sb = new StringBuilder(32); | 
|  | // WARNING: Do not change the format of this string, it must be | 
|  | // preserved because Rects are saved in this flattened format. | 
|  | sb.append(left); | 
|  | sb.append(' '); | 
|  | sb.append(top); | 
|  | sb.append(' '); | 
|  | sb.append(right); | 
|  | sb.append(' '); | 
|  | sb.append(bottom); | 
|  | return sb.toString(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a Rect from a string of the form returned by {@link #flattenToString}, | 
|  | * or null if the string is not of that form. | 
|  | */ | 
|  | @Nullable | 
|  | public static Rect unflattenFromString(@Nullable String str) { | 
|  | if (TextUtils.isEmpty(str)) { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | Matcher matcher = UnflattenHelper.getMatcher(str); | 
|  | if (!matcher.matches()) { | 
|  | return null; | 
|  | } | 
|  | return new Rect(Integer.parseInt(matcher.group(1)), | 
|  | Integer.parseInt(matcher.group(2)), | 
|  | Integer.parseInt(matcher.group(3)), | 
|  | Integer.parseInt(matcher.group(4))); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Print short representation to given writer. | 
|  | * @hide | 
|  | */ | 
|  | @UnsupportedAppUsage | 
|  | public void printShortString(@NonNull PrintWriter pw) { | 
|  | pw.print('['); pw.print(left); pw.print(','); | 
|  | pw.print(top); pw.print("]["); pw.print(right); | 
|  | pw.print(','); pw.print(bottom); pw.print(']'); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Write to a protocol buffer output stream. | 
|  | * Protocol buffer message definition at {@link android.graphics.RectProto} | 
|  | * | 
|  | * @param protoOutputStream Stream to write the Rect object to. | 
|  | * @param fieldId           Field Id of the Rect as defined in the parent message | 
|  | * @hide | 
|  | */ | 
|  | public void dumpDebug(@NonNull ProtoOutputStream protoOutputStream, long fieldId) { | 
|  | final long token = protoOutputStream.start(fieldId); | 
|  | protoOutputStream.write(RectProto.LEFT, left); | 
|  | protoOutputStream.write(RectProto.TOP, top); | 
|  | protoOutputStream.write(RectProto.RIGHT, right); | 
|  | protoOutputStream.write(RectProto.BOTTOM, bottom); | 
|  | protoOutputStream.end(token); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Read from a protocol buffer input stream. | 
|  | * Protocol buffer message definition at {@link android.graphics.RectProto} | 
|  | * | 
|  | * @param proto     Stream to read the Rect object from. | 
|  | * @param fieldId   Field Id of the Rect as defined in the parent message | 
|  | * @hide | 
|  | */ | 
|  | public void readFromProto(@NonNull ProtoInputStream proto, long fieldId) throws IOException, | 
|  | WireTypeMismatchException { | 
|  | final long token = proto.start(fieldId); | 
|  | try { | 
|  | while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { | 
|  | switch (proto.getFieldNumber()) { | 
|  | case (int) RectProto.LEFT: | 
|  | left = proto.readInt(RectProto.LEFT); | 
|  | break; | 
|  | case (int) RectProto.TOP: | 
|  | top = proto.readInt(RectProto.TOP); | 
|  | break; | 
|  | case (int) RectProto.RIGHT: | 
|  | right = proto.readInt(RectProto.RIGHT); | 
|  | break; | 
|  | case (int) RectProto.BOTTOM: | 
|  | bottom = proto.readInt(RectProto.BOTTOM); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } finally { | 
|  | // Let caller handle any exceptions | 
|  | proto.end(token); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if the rectangle is empty (left >= right or top >= bottom) | 
|  | */ | 
|  | public final boolean isEmpty() { | 
|  | return left >= right || top >= bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return {@code true} if the rectangle is valid (left <= right and top <= bottom). | 
|  | * @hide | 
|  | */ | 
|  | public boolean isValid() { | 
|  | return left <= right && top <= bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the rectangle's width. This does not check for a valid rectangle | 
|  | * (i.e. left <= right) so the result may be negative. | 
|  | */ | 
|  | public final int width() { | 
|  | return right - left; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the rectangle's height. This does not check for a valid rectangle | 
|  | * (i.e. top <= bottom) so the result may be negative. | 
|  | */ | 
|  | public final int height() { | 
|  | return bottom - top; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the horizontal center of the rectangle. If the computed value | 
|  | *         is fractional, this method returns the largest integer that is | 
|  | *         less than the computed value. | 
|  | */ | 
|  | public final int centerX() { | 
|  | return (left + right) >> 1; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the vertical center of the rectangle. If the computed value | 
|  | *         is fractional, this method returns the largest integer that is | 
|  | *         less than the computed value. | 
|  | */ | 
|  | public final int centerY() { | 
|  | return (top + bottom) >> 1; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the exact horizontal center of the rectangle as a float. | 
|  | */ | 
|  | public final float exactCenterX() { | 
|  | return (left + right) * 0.5f; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the exact vertical center of the rectangle as a float. | 
|  | */ | 
|  | public final float exactCenterY() { | 
|  | return (top + bottom) * 0.5f; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the rectangle to (0,0,0,0) | 
|  | */ | 
|  | public void setEmpty() { | 
|  | left = right = top = bottom = 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the rectangle's coordinates to the specified values. Note: no range | 
|  | * checking is performed, so it is up to the caller to ensure that | 
|  | * left <= right and top <= bottom. | 
|  | * | 
|  | * @param left   The X coordinate of the left side of the rectangle | 
|  | * @param top    The Y coordinate of the top of the rectangle | 
|  | * @param right  The X coordinate of the right side of the rectangle | 
|  | * @param bottom The Y coordinate of the bottom of the rectangle | 
|  | */ | 
|  | public void set(int left, int top, int right, int bottom) { | 
|  | this.left = left; | 
|  | this.top = top; | 
|  | this.right = right; | 
|  | this.bottom = bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Copy the coordinates from src into this rectangle. | 
|  | * | 
|  | * @param src The rectangle whose coordinates are copied into this | 
|  | *           rectangle. | 
|  | */ | 
|  | public void set(@NonNull Rect src) { | 
|  | this.left = src.left; | 
|  | this.top = src.top; | 
|  | this.right = src.right; | 
|  | this.bottom = src.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Offset the rectangle by adding dx to its left and right coordinates, and | 
|  | * adding dy to its top and bottom coordinates. | 
|  | * | 
|  | * @param dx The amount to add to the rectangle's left and right coordinates | 
|  | * @param dy The amount to add to the rectangle's top and bottom coordinates | 
|  | */ | 
|  | public void offset(int dx, int dy) { | 
|  | left += dx; | 
|  | top += dy; | 
|  | right += dx; | 
|  | bottom += dy; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Offset the rectangle to a specific (left, top) position, | 
|  | * keeping its width and height the same. | 
|  | * | 
|  | * @param newLeft   The new "left" coordinate for the rectangle | 
|  | * @param newTop    The new "top" coordinate for the rectangle | 
|  | */ | 
|  | public void offsetTo(int newLeft, int newTop) { | 
|  | right += newLeft - left; | 
|  | bottom += newTop - top; | 
|  | left = newLeft; | 
|  | top = newTop; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Inset the rectangle by (dx,dy). If dx is positive, then the sides are | 
|  | * moved inwards, making the rectangle narrower. If dx is negative, then the | 
|  | * sides are moved outwards, making the rectangle wider. The same holds true | 
|  | * for dy and the top and bottom. | 
|  | * | 
|  | * @param dx The amount to add(subtract) from the rectangle's left(right) | 
|  | * @param dy The amount to add(subtract) from the rectangle's top(bottom) | 
|  | */ | 
|  | public void inset(int dx, int dy) { | 
|  | left += dx; | 
|  | top += dy; | 
|  | right -= dx; | 
|  | bottom -= dy; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Insets the rectangle on all sides specified by the dimensions of the {@code insets} | 
|  | * rectangle. | 
|  | * @hide | 
|  | * @param insets The rectangle specifying the insets on all side. | 
|  | */ | 
|  | public void inset(@NonNull Rect insets) { | 
|  | left += insets.left; | 
|  | top += insets.top; | 
|  | right -= insets.right; | 
|  | bottom -= insets.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Insets the rectangle on all sides specified by the dimensions of {@code insets}. | 
|  | * | 
|  | * @param insets The insets to inset the rect by. | 
|  | */ | 
|  | public void inset(@NonNull Insets insets) { | 
|  | left += insets.left; | 
|  | top += insets.top; | 
|  | right -= insets.right; | 
|  | bottom -= insets.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Insets the rectangle on all sides specified by the insets. | 
|  | * | 
|  | * @param left The amount to add from the rectangle's left | 
|  | * @param top The amount to add from the rectangle's top | 
|  | * @param right The amount to subtract from the rectangle's right | 
|  | * @param bottom The amount to subtract from the rectangle's bottom | 
|  | */ | 
|  | public void inset(int left, int top, int right, int bottom) { | 
|  | this.left += left; | 
|  | this.top += top; | 
|  | this.right -= right; | 
|  | this.bottom -= bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if (x,y) is inside the rectangle. The left and top are | 
|  | * considered to be inside, while the right and bottom are not. This means | 
|  | * that for a x,y to be contained: left <= x < right and top <= y < bottom. | 
|  | * An empty rectangle never contains any point. | 
|  | * | 
|  | * @param x The X coordinate of the point being tested for containment | 
|  | * @param y The Y coordinate of the point being tested for containment | 
|  | * @return true iff (x,y) are contained by the rectangle, where containment | 
|  | *              means left <= x < right and top <= y < bottom | 
|  | */ | 
|  | public boolean contains(int x, int y) { | 
|  | return left < right && top < bottom  // check for empty first | 
|  | && x >= left && x < right && y >= top && y < bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true iff the 4 specified sides of a rectangle are inside or equal | 
|  | * to this rectangle. i.e. is this rectangle a superset of the specified | 
|  | * rectangle. An empty rectangle never contains another rectangle. | 
|  | * | 
|  | * @param left The left side of the rectangle being tested for containment | 
|  | * @param top The top of the rectangle being tested for containment | 
|  | * @param right The right side of the rectangle being tested for containment | 
|  | * @param bottom The bottom of the rectangle being tested for containment | 
|  | * @return true iff the 4 specified sides of a rectangle are inside or | 
|  | *              equal to this rectangle | 
|  | */ | 
|  | public boolean contains(int left, int top, int right, int bottom) { | 
|  | // check for empty first | 
|  | return this.left < this.right && this.top < this.bottom | 
|  | // now check for containment | 
|  | && this.left <= left && this.top <= top | 
|  | && this.right >= right && this.bottom >= bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true iff the specified rectangle r is inside or equal to this | 
|  | * rectangle. An empty rectangle never contains another rectangle. | 
|  | * | 
|  | * @param r The rectangle being tested for containment. | 
|  | * @return true iff the specified rectangle r is inside or equal to this | 
|  | *              rectangle | 
|  | */ | 
|  | public boolean contains(@NonNull Rect r) { | 
|  | // check for empty first | 
|  | return this.left < this.right && this.top < this.bottom | 
|  | // now check for containment | 
|  | && left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * If the rectangle specified by left,top,right,bottom intersects this | 
|  | * rectangle, return true and set this rectangle to that intersection, | 
|  | * otherwise return false and do not change this rectangle. No check is | 
|  | * performed to see if either rectangle is empty. Note: To just test for | 
|  | * intersection, use {@link #intersects(Rect, Rect)}. | 
|  | * | 
|  | * @param left The left side of the rectangle being intersected with this | 
|  | *             rectangle | 
|  | * @param top The top of the rectangle being intersected with this rectangle | 
|  | * @param right The right side of the rectangle being intersected with this | 
|  | *              rectangle. | 
|  | * @param bottom The bottom of the rectangle being intersected with this | 
|  | *             rectangle. | 
|  | * @return true if the specified rectangle and this rectangle intersect | 
|  | *              (and this rectangle is then set to that intersection) else | 
|  | *              return false and do not change this rectangle. | 
|  | */ | 
|  | @CheckResult | 
|  | public boolean intersect(int left, int top, int right, int bottom) { | 
|  | if (this.left < right && left < this.right && this.top < bottom && top < this.bottom) { | 
|  | if (this.left < left) this.left = left; | 
|  | if (this.top < top) this.top = top; | 
|  | if (this.right > right) this.right = right; | 
|  | if (this.bottom > bottom) this.bottom = bottom; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * If the specified rectangle intersects this rectangle, return true and set | 
|  | * this rectangle to that intersection, otherwise return false and do not | 
|  | * change this rectangle. No check is performed to see if either rectangle | 
|  | * is empty. To just test for intersection, use intersects() | 
|  | * | 
|  | * @param r The rectangle being intersected with this rectangle. | 
|  | * @return true if the specified rectangle and this rectangle intersect | 
|  | *              (and this rectangle is then set to that intersection) else | 
|  | *              return false and do not change this rectangle. | 
|  | */ | 
|  | @CheckResult | 
|  | public boolean intersect(@NonNull Rect r) { | 
|  | return intersect(r.left, r.top, r.right, r.bottom); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * If the specified rectangle intersects this rectangle, set this rectangle to that | 
|  | * intersection, otherwise set this rectangle to the empty rectangle. | 
|  | * @see #inset(int, int, int, int) but without checking if the rects overlap. | 
|  | * @hide | 
|  | */ | 
|  | public void intersectUnchecked(@NonNull Rect other) { | 
|  | left = Math.max(left, other.left); | 
|  | top = Math.max(top, other.top); | 
|  | right = Math.min(right, other.right); | 
|  | bottom = Math.min(bottom, other.bottom); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * If rectangles a and b intersect, return true and set this rectangle to | 
|  | * that intersection, otherwise return false and do not change this | 
|  | * rectangle. No check is performed to see if either rectangle is empty. | 
|  | * To just test for intersection, use intersects() | 
|  | * | 
|  | * @param a The first rectangle being intersected with | 
|  | * @param b The second rectangle being intersected with | 
|  | * @return true iff the two specified rectangles intersect. If they do, set | 
|  | *              this rectangle to that intersection. If they do not, return | 
|  | *              false and do not change this rectangle. | 
|  | */ | 
|  | @CheckResult | 
|  | public boolean setIntersect(@NonNull Rect a, @NonNull Rect b) { | 
|  | if (a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom) { | 
|  | left = Math.max(a.left, b.left); | 
|  | top = Math.max(a.top, b.top); | 
|  | right = Math.min(a.right, b.right); | 
|  | bottom = Math.min(a.bottom, b.bottom); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if this rectangle intersects the specified rectangle. | 
|  | * In no event is this rectangle modified. No check is performed to see | 
|  | * if either rectangle is empty. To record the intersection, use intersect() | 
|  | * or setIntersect(). | 
|  | * | 
|  | * @param left The left side of the rectangle being tested for intersection | 
|  | * @param top The top of the rectangle being tested for intersection | 
|  | * @param right The right side of the rectangle being tested for | 
|  | *              intersection | 
|  | * @param bottom The bottom of the rectangle being tested for intersection | 
|  | * @return true iff the specified rectangle intersects this rectangle. In | 
|  | *              no event is this rectangle modified. | 
|  | */ | 
|  | public boolean intersects(int left, int top, int right, int bottom) { | 
|  | return this.left < right && left < this.right && this.top < bottom && top < this.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true iff the two specified rectangles intersect. In no event are | 
|  | * either of the rectangles modified. To record the intersection, | 
|  | * use {@link #intersect(Rect)} or {@link #setIntersect(Rect, Rect)}. | 
|  | * | 
|  | * @param a The first rectangle being tested for intersection | 
|  | * @param b The second rectangle being tested for intersection | 
|  | * @return true iff the two specified rectangles intersect. In no event are | 
|  | *              either of the rectangles modified. | 
|  | */ | 
|  | public static boolean intersects(@NonNull Rect a, @NonNull Rect b) { | 
|  | return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Update this Rect to enclose itself and the specified rectangle. If the | 
|  | * specified rectangle is empty, nothing is done. If this rectangle is empty | 
|  | * it is set to the specified rectangle. | 
|  | * | 
|  | * @param left The left edge being unioned with this rectangle | 
|  | * @param top The top edge being unioned with this rectangle | 
|  | * @param right The right edge being unioned with this rectangle | 
|  | * @param bottom The bottom edge being unioned with this rectangle | 
|  | */ | 
|  | public void union(int left, int top, int right, int bottom) { | 
|  | if ((left < right) && (top < bottom)) { | 
|  | if ((this.left < this.right) && (this.top < this.bottom)) { | 
|  | if (this.left > left) this.left = left; | 
|  | if (this.top > top) this.top = top; | 
|  | if (this.right < right) this.right = right; | 
|  | if (this.bottom < bottom) this.bottom = bottom; | 
|  | } else { | 
|  | this.left = left; | 
|  | this.top = top; | 
|  | this.right = right; | 
|  | this.bottom = bottom; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Update this Rect to enclose itself and the specified rectangle. If the | 
|  | * specified rectangle is empty, nothing is done. If this rectangle is empty | 
|  | * it is set to the specified rectangle. | 
|  | * | 
|  | * @param r The rectangle being unioned with this rectangle | 
|  | */ | 
|  | public void union(@NonNull Rect r) { | 
|  | union(r.left, r.top, r.right, r.bottom); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Update this Rect to enclose itself and the [x,y] coordinate. There is no | 
|  | * check to see that this rectangle is non-empty. | 
|  | * | 
|  | * @param x The x coordinate of the point to add to the rectangle | 
|  | * @param y The y coordinate of the point to add to the rectangle | 
|  | */ | 
|  | public void union(int x, int y) { | 
|  | if (x < left) { | 
|  | left = x; | 
|  | } else if (x > right) { | 
|  | right = x; | 
|  | } | 
|  | if (y < top) { | 
|  | top = y; | 
|  | } else if (y > bottom) { | 
|  | bottom = y; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Swap top/bottom or left/right if there are flipped (i.e. left > right | 
|  | * and/or top > bottom). This can be called if | 
|  | * the edges are computed separately, and may have crossed over each other. | 
|  | * If the edges are already correct (i.e. left <= right and top <= bottom) | 
|  | * then nothing is done. | 
|  | */ | 
|  | public void sort() { | 
|  | if (left > right) { | 
|  | int temp = left; | 
|  | left = right; | 
|  | right = temp; | 
|  | } | 
|  | if (top > bottom) { | 
|  | int temp = top; | 
|  | top = bottom; | 
|  | bottom = temp; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Splits this Rect into small rects of the same width. | 
|  | * @hide | 
|  | */ | 
|  | @TestApi | 
|  | public void splitVertically(@NonNull Rect ...splits) { | 
|  | final int count = splits.length; | 
|  | final int splitWidth = width() / count; | 
|  | for (int i = 0; i < count; i++) { | 
|  | final Rect split = splits[i]; | 
|  | split.left = left + (splitWidth * i); | 
|  | split.top = top; | 
|  | split.right = split.left + splitWidth; | 
|  | split.bottom = bottom; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Splits this Rect into small rects of the same height. | 
|  | * @hide | 
|  | */ | 
|  | @TestApi | 
|  | public void splitHorizontally(@NonNull Rect ...outSplits) { | 
|  | final int count = outSplits.length; | 
|  | final int splitHeight = height() / count; | 
|  | for (int i = 0; i < count; i++) { | 
|  | final Rect split = outSplits[i]; | 
|  | split.left = left; | 
|  | split.top = top + (splitHeight * i); | 
|  | split.right = right; | 
|  | split.bottom = split.top + splitHeight; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parcelable interface methods | 
|  | */ | 
|  | @Override | 
|  | public int describeContents() { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Write this rectangle to the specified parcel. To restore a rectangle from | 
|  | * a parcel, use readFromParcel() | 
|  | * @param out The parcel to write the rectangle's coordinates into | 
|  | */ | 
|  | @Override | 
|  | public void writeToParcel(Parcel out, int flags) { | 
|  | out.writeInt(left); | 
|  | out.writeInt(top); | 
|  | out.writeInt(right); | 
|  | out.writeInt(bottom); | 
|  | } | 
|  |  | 
|  | public static final @android.annotation.NonNull Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() { | 
|  | /** | 
|  | * Return a new rectangle from the data in the specified parcel. | 
|  | */ | 
|  | @Override | 
|  | public Rect createFromParcel(Parcel in) { | 
|  | Rect r = new Rect(); | 
|  | r.readFromParcel(in); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return an array of rectangles of the specified size. | 
|  | */ | 
|  | @Override | 
|  | public Rect[] newArray(int size) { | 
|  | return new Rect[size]; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Set the rectangle's coordinates from the data stored in the specified | 
|  | * parcel. To write a rectangle to a parcel, call writeToParcel(). | 
|  | * | 
|  | * @param in The parcel to read the rectangle's coordinates from | 
|  | */ | 
|  | public void readFromParcel(@NonNull Parcel in) { | 
|  | left = in.readInt(); | 
|  | top = in.readInt(); | 
|  | right = in.readInt(); | 
|  | bottom = in.readInt(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Scales up the rect by the given scale. | 
|  | * @hide | 
|  | */ | 
|  | @UnsupportedAppUsage | 
|  | public void scale(float scale) { | 
|  | if (scale != 1.0f) { | 
|  | left = (int) (left * scale + 0.5f); | 
|  | top = (int) (top * scale + 0.5f); | 
|  | right = (int) (right * scale + 0.5f); | 
|  | bottom = (int) (bottom * scale + 0.5f); | 
|  | } | 
|  | } | 
|  |  | 
|  | } |