1 /*
2  * Copyright (C) 2006 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.graphics;
18 
19 import android.annotation.CheckResult;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.text.TextUtils;
26 import android.util.proto.ProtoInputStream;
27 import android.util.proto.ProtoOutputStream;
28 import android.util.proto.WireTypeMismatchException;
29 
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 
35 /**
36  * Rect holds four integer coordinates for a rectangle. The rectangle is
37  * represented by the coordinates of its 4 edges (left, top, right bottom).
38  * These fields can be accessed directly. Use width() and height() to retrieve
39  * the rectangle's width and height. Note: most methods do not check to see that
40  * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
41  * <p>
42  * Note that the right and bottom coordinates are exclusive. This means a Rect
43  * being drawn untransformed onto a {@link android.graphics.Canvas} will draw
44  * into the column and row described by its left and top coordinates, but not
45  * those of its bottom and right.
46  */
47 public final class Rect implements Parcelable {
48     public int left;
49     public int top;
50     public int right;
51     public int bottom;
52 
53     /**
54      * A helper class for flattened rectange pattern recognition. A separate
55      * class to avoid an initialization dependency on a regular expression
56      * causing Rect to not be initializable with an ahead-of-time compilation
57      * scheme.
58      */
59     private static final class UnflattenHelper {
60         private static final Pattern FLATTENED_PATTERN = Pattern.compile(
61             "(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");
62 
getMatcher(String str)63         static Matcher getMatcher(String str) {
64             return FLATTENED_PATTERN.matcher(str);
65         }
66     }
67 
68     /**
69      * Create a new empty Rect. All coordinates are initialized to 0.
70      */
Rect()71     public Rect() {}
72 
73     /**
74      * Create a new rectangle with the specified coordinates. Note: no range
75      * checking is performed, so the caller must ensure that left <= right and
76      * top <= bottom.
77      *
78      * @param left   The X coordinate of the left side of the rectangle
79      * @param top    The Y coordinate of the top of the rectangle
80      * @param right  The X coordinate of the right side of the rectangle
81      * @param bottom The Y coordinate of the bottom of the rectangle
82      */
Rect(int left, int top, int right, int bottom)83     public Rect(int left, int top, int right, int bottom) {
84         this.left = left;
85         this.top = top;
86         this.right = right;
87         this.bottom = bottom;
88     }
89 
90     /**
91      * Create a new rectangle, initialized with the values in the specified
92      * rectangle (which is left unmodified).
93      *
94      * @param r The rectangle whose coordinates are copied into the new
95      *          rectangle.
96      */
Rect(@ullable Rect r)97     public Rect(@Nullable Rect r) {
98         if (r == null) {
99             left = top = right = bottom = 0;
100         } else {
101             left = r.left;
102             top = r.top;
103             right = r.right;
104             bottom = r.bottom;
105         }
106     }
107 
108     /**
109      * @hide
110      */
Rect(@ullable Insets r)111     public Rect(@Nullable Insets r) {
112         if (r == null) {
113             left = top = right = bottom = 0;
114         } else {
115             left = r.left;
116             top = r.top;
117             right = r.right;
118             bottom = r.bottom;
119         }
120     }
121 
122     /**
123      * Returns a copy of {@code r} if {@code r} is not {@code null}, or {@code null} otherwise.
124      *
125      * @hide
126      */
127     @Nullable
copyOrNull(@ullable Rect r)128     public static Rect copyOrNull(@Nullable Rect r) {
129         return r == null ? null : new Rect(r);
130     }
131 
132     @Override
equals(Object o)133     public boolean equals(Object o) {
134         if (this == o) return true;
135         if (o == null || getClass() != o.getClass()) return false;
136 
137         Rect r = (Rect) o;
138         return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
139     }
140 
141     @Override
hashCode()142     public int hashCode() {
143         int result = left;
144         result = 31 * result + top;
145         result = 31 * result + right;
146         result = 31 * result + bottom;
147         return result;
148     }
149 
150     @Override
toString()151     public String toString() {
152         StringBuilder sb = new StringBuilder(32);
153         sb.append("Rect("); sb.append(left); sb.append(", ");
154         sb.append(top); sb.append(" - "); sb.append(right);
155         sb.append(", "); sb.append(bottom); sb.append(")");
156         return sb.toString();
157     }
158 
159     /**
160      * Return a string representation of the rectangle in a compact form.
161      */
162     @NonNull
toShortString()163     public String toShortString() {
164         return toShortString(new StringBuilder(32));
165     }
166 
167     /**
168      * Return a string representation of the rectangle in a compact form.
169      * @hide
170      */
171     @NonNull
toShortString(@onNull StringBuilder sb)172     public String toShortString(@NonNull StringBuilder sb) {
173         sb.setLength(0);
174         sb.append('['); sb.append(left); sb.append(',');
175         sb.append(top); sb.append("]["); sb.append(right);
176         sb.append(','); sb.append(bottom); sb.append(']');
177         return sb.toString();
178     }
179 
180     /**
181      * Return a string representation of the rectangle in a well-defined format.
182      *
183      * <p>You can later recover the Rect from this string through
184      * {@link #unflattenFromString(String)}.
185      *
186      * @return Returns a new String of the form "left top right bottom"
187      */
188     @NonNull
flattenToString()189     public String flattenToString() {
190         StringBuilder sb = new StringBuilder(32);
191         // WARNING: Do not change the format of this string, it must be
192         // preserved because Rects are saved in this flattened format.
193         sb.append(left);
194         sb.append(' ');
195         sb.append(top);
196         sb.append(' ');
197         sb.append(right);
198         sb.append(' ');
199         sb.append(bottom);
200         return sb.toString();
201     }
202 
203     /**
204      * Returns a Rect from a string of the form returned by {@link #flattenToString},
205      * or null if the string is not of that form.
206      */
207     @Nullable
unflattenFromString(@ullable String str)208     public static Rect unflattenFromString(@Nullable String str) {
209         if (TextUtils.isEmpty(str)) {
210             return null;
211         }
212 
213         Matcher matcher = UnflattenHelper.getMatcher(str);
214         if (!matcher.matches()) {
215             return null;
216         }
217         return new Rect(Integer.parseInt(matcher.group(1)),
218                 Integer.parseInt(matcher.group(2)),
219                 Integer.parseInt(matcher.group(3)),
220                 Integer.parseInt(matcher.group(4)));
221     }
222 
223     /**
224      * Print short representation to given writer.
225      * @hide
226      */
227     @UnsupportedAppUsage
printShortString(@onNull PrintWriter pw)228     public void printShortString(@NonNull PrintWriter pw) {
229         pw.print('['); pw.print(left); pw.print(',');
230         pw.print(top); pw.print("]["); pw.print(right);
231         pw.print(','); pw.print(bottom); pw.print(']');
232     }
233 
234     /**
235      * Write to a protocol buffer output stream.
236      * Protocol buffer message definition at {@link android.graphics.RectProto}
237      *
238      * @param protoOutputStream Stream to write the Rect object to.
239      * @param fieldId           Field Id of the Rect as defined in the parent message
240      * @hide
241      */
writeToProto(@onNull ProtoOutputStream protoOutputStream, long fieldId)242     public void writeToProto(@NonNull ProtoOutputStream protoOutputStream, long fieldId) {
243         final long token = protoOutputStream.start(fieldId);
244         protoOutputStream.write(RectProto.LEFT, left);
245         protoOutputStream.write(RectProto.TOP, top);
246         protoOutputStream.write(RectProto.RIGHT, right);
247         protoOutputStream.write(RectProto.BOTTOM, bottom);
248         protoOutputStream.end(token);
249     }
250 
251     /**
252      * Read from a protocol buffer input stream.
253      * Protocol buffer message definition at {@link android.graphics.RectProto}
254      *
255      * @param proto     Stream to read the Rect object from.
256      * @param fieldId   Field Id of the Rect as defined in the parent message
257      * @hide
258      */
readFromProto(@onNull ProtoInputStream proto, long fieldId)259     public void readFromProto(@NonNull ProtoInputStream proto, long fieldId) throws IOException,
260             WireTypeMismatchException {
261         final long token = proto.start(fieldId);
262         try {
263             while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
264                 switch (proto.getFieldNumber()) {
265                     case (int) RectProto.LEFT:
266                         left = proto.readInt(RectProto.LEFT);
267                         break;
268                     case (int) RectProto.TOP:
269                         top = proto.readInt(RectProto.TOP);
270                         break;
271                     case (int) RectProto.RIGHT:
272                         right = proto.readInt(RectProto.RIGHT);
273                         break;
274                     case (int) RectProto.BOTTOM:
275                         bottom = proto.readInt(RectProto.BOTTOM);
276                         break;
277                 }
278             }
279         } finally {
280             // Let caller handle any exceptions
281             proto.end(token);
282         }
283     }
284 
285     /**
286      * Returns true if the rectangle is empty (left >= right or top >= bottom)
287      */
isEmpty()288     public final boolean isEmpty() {
289         return left >= right || top >= bottom;
290     }
291 
292     /**
293      * @return the rectangle's width. This does not check for a valid rectangle
294      * (i.e. left <= right) so the result may be negative.
295      */
width()296     public final int width() {
297         return right - left;
298     }
299 
300     /**
301      * @return the rectangle's height. This does not check for a valid rectangle
302      * (i.e. top <= bottom) so the result may be negative.
303      */
height()304     public final int height() {
305         return bottom - top;
306     }
307 
308     /**
309      * @return the horizontal center of the rectangle. If the computed value
310      *         is fractional, this method returns the largest integer that is
311      *         less than the computed value.
312      */
centerX()313     public final int centerX() {
314         return (left + right) >> 1;
315     }
316 
317     /**
318      * @return the vertical center of the rectangle. If the computed value
319      *         is fractional, this method returns the largest integer that is
320      *         less than the computed value.
321      */
centerY()322     public final int centerY() {
323         return (top + bottom) >> 1;
324     }
325 
326     /**
327      * @return the exact horizontal center of the rectangle as a float.
328      */
exactCenterX()329     public final float exactCenterX() {
330         return (left + right) * 0.5f;
331     }
332 
333     /**
334      * @return the exact vertical center of the rectangle as a float.
335      */
exactCenterY()336     public final float exactCenterY() {
337         return (top + bottom) * 0.5f;
338     }
339 
340     /**
341      * Set the rectangle to (0,0,0,0)
342      */
setEmpty()343     public void setEmpty() {
344         left = right = top = bottom = 0;
345     }
346 
347     /**
348      * Set the rectangle's coordinates to the specified values. Note: no range
349      * checking is performed, so it is up to the caller to ensure that
350      * left <= right and top <= bottom.
351      *
352      * @param left   The X coordinate of the left side of the rectangle
353      * @param top    The Y coordinate of the top of the rectangle
354      * @param right  The X coordinate of the right side of the rectangle
355      * @param bottom The Y coordinate of the bottom of the rectangle
356      */
set(int left, int top, int right, int bottom)357     public void set(int left, int top, int right, int bottom) {
358         this.left = left;
359         this.top = top;
360         this.right = right;
361         this.bottom = bottom;
362     }
363 
364     /**
365      * Copy the coordinates from src into this rectangle.
366      *
367      * @param src The rectangle whose coordinates are copied into this
368      *           rectangle.
369      */
set(@onNull Rect src)370     public void set(@NonNull Rect src) {
371         this.left = src.left;
372         this.top = src.top;
373         this.right = src.right;
374         this.bottom = src.bottom;
375     }
376 
377     /**
378      * Offset the rectangle by adding dx to its left and right coordinates, and
379      * adding dy to its top and bottom coordinates.
380      *
381      * @param dx The amount to add to the rectangle's left and right coordinates
382      * @param dy The amount to add to the rectangle's top and bottom coordinates
383      */
offset(int dx, int dy)384     public void offset(int dx, int dy) {
385         left += dx;
386         top += dy;
387         right += dx;
388         bottom += dy;
389     }
390 
391     /**
392      * Offset the rectangle to a specific (left, top) position,
393      * keeping its width and height the same.
394      *
395      * @param newLeft   The new "left" coordinate for the rectangle
396      * @param newTop    The new "top" coordinate for the rectangle
397      */
offsetTo(int newLeft, int newTop)398     public void offsetTo(int newLeft, int newTop) {
399         right += newLeft - left;
400         bottom += newTop - top;
401         left = newLeft;
402         top = newTop;
403     }
404 
405     /**
406      * Inset the rectangle by (dx,dy). If dx is positive, then the sides are
407      * moved inwards, making the rectangle narrower. If dx is negative, then the
408      * sides are moved outwards, making the rectangle wider. The same holds true
409      * for dy and the top and bottom.
410      *
411      * @param dx The amount to add(subtract) from the rectangle's left(right)
412      * @param dy The amount to add(subtract) from the rectangle's top(bottom)
413      */
inset(int dx, int dy)414     public void inset(int dx, int dy) {
415         left += dx;
416         top += dy;
417         right -= dx;
418         bottom -= dy;
419     }
420 
421     /**
422      * Insets the rectangle on all sides specified by the dimensions of the {@code insets}
423      * rectangle.
424      * @hide
425      * @param insets The rectangle specifying the insets on all side.
426      */
inset(@onNull Rect insets)427     public void inset(@NonNull Rect insets) {
428         left += insets.left;
429         top += insets.top;
430         right -= insets.right;
431         bottom -= insets.bottom;
432     }
433 
434     /**
435      * Insets the rectangle on all sides specified by the dimensions of {@code insets}.
436      * @hide
437      * @param insets The insets to inset the rect by.
438      */
inset(Insets insets)439     public void inset(Insets insets) {
440         left += insets.left;
441         top += insets.top;
442         right -= insets.right;
443         bottom -= insets.bottom;
444     }
445 
446     /**
447      * Insets the rectangle on all sides specified by the insets.
448      * @hide
449      * @param left The amount to add from the rectangle's left
450      * @param top The amount to add from the rectangle's top
451      * @param right The amount to subtract from the rectangle's right
452      * @param bottom The amount to subtract from the rectangle's bottom
453      */
inset(int left, int top, int right, int bottom)454     public void inset(int left, int top, int right, int bottom) {
455         this.left += left;
456         this.top += top;
457         this.right -= right;
458         this.bottom -= bottom;
459     }
460 
461     /**
462      * Returns true if (x,y) is inside the rectangle. The left and top are
463      * considered to be inside, while the right and bottom are not. This means
464      * that for a x,y to be contained: left <= x < right and top <= y < bottom.
465      * An empty rectangle never contains any point.
466      *
467      * @param x The X coordinate of the point being tested for containment
468      * @param y The Y coordinate of the point being tested for containment
469      * @return true iff (x,y) are contained by the rectangle, where containment
470      *              means left <= x < right and top <= y < bottom
471      */
contains(int x, int y)472     public boolean contains(int x, int y) {
473         return left < right && top < bottom  // check for empty first
474                && x >= left && x < right && y >= top && y < bottom;
475     }
476 
477     /**
478      * Returns true iff the 4 specified sides of a rectangle are inside or equal
479      * to this rectangle. i.e. is this rectangle a superset of the specified
480      * rectangle. An empty rectangle never contains another rectangle.
481      *
482      * @param left The left side of the rectangle being tested for containment
483      * @param top The top of the rectangle being tested for containment
484      * @param right The right side of the rectangle being tested for containment
485      * @param bottom The bottom of the rectangle being tested for containment
486      * @return true iff the the 4 specified sides of a rectangle are inside or
487      *              equal to this rectangle
488      */
contains(int left, int top, int right, int bottom)489     public boolean contains(int left, int top, int right, int bottom) {
490                // check for empty first
491         return this.left < this.right && this.top < this.bottom
492                // now check for containment
493                 && this.left <= left && this.top <= top
494                 && this.right >= right && this.bottom >= bottom;
495     }
496 
497     /**
498      * Returns true iff the specified rectangle r is inside or equal to this
499      * rectangle. An empty rectangle never contains another rectangle.
500      *
501      * @param r The rectangle being tested for containment.
502      * @return true iff the specified rectangle r is inside or equal to this
503      *              rectangle
504      */
contains(@onNull Rect r)505     public boolean contains(@NonNull Rect r) {
506                // check for empty first
507         return this.left < this.right && this.top < this.bottom
508                // now check for containment
509                && left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom;
510     }
511 
512     /**
513      * If the rectangle specified by left,top,right,bottom intersects this
514      * rectangle, return true and set this rectangle to that intersection,
515      * otherwise return false and do not change this rectangle. No check is
516      * performed to see if either rectangle is empty. Note: To just test for
517      * intersection, use {@link #intersects(Rect, Rect)}.
518      *
519      * @param left The left side of the rectangle being intersected with this
520      *             rectangle
521      * @param top The top of the rectangle being intersected with this rectangle
522      * @param right The right side of the rectangle being intersected with this
523      *              rectangle.
524      * @param bottom The bottom of the rectangle being intersected with this
525      *             rectangle.
526      * @return true if the specified rectangle and this rectangle intersect
527      *              (and this rectangle is then set to that intersection) else
528      *              return false and do not change this rectangle.
529      */
530     @CheckResult
intersect(int left, int top, int right, int bottom)531     public boolean intersect(int left, int top, int right, int bottom) {
532         if (this.left < right && left < this.right && this.top < bottom && top < this.bottom) {
533             if (this.left < left) this.left = left;
534             if (this.top < top) this.top = top;
535             if (this.right > right) this.right = right;
536             if (this.bottom > bottom) this.bottom = bottom;
537             return true;
538         }
539         return false;
540     }
541 
542     /**
543      * If the specified rectangle intersects this rectangle, return true and set
544      * this rectangle to that intersection, otherwise return false and do not
545      * change this rectangle. No check is performed to see if either rectangle
546      * is empty. To just test for intersection, use intersects()
547      *
548      * @param r The rectangle being intersected with this rectangle.
549      * @return true if the specified rectangle and this rectangle intersect
550      *              (and this rectangle is then set to that intersection) else
551      *              return false and do not change this rectangle.
552      */
553     @CheckResult
intersect(@onNull Rect r)554     public boolean intersect(@NonNull Rect r) {
555         return intersect(r.left, r.top, r.right, r.bottom);
556     }
557 
558     /**
559      * If the specified rectangle intersects this rectangle, set this rectangle to that
560      * intersection, otherwise set this rectangle to the empty rectangle.
561      * @see #inset(int, int, int, int) but without checking if the rects overlap.
562      * @hide
563      */
intersectUnchecked(@onNull Rect other)564     public void intersectUnchecked(@NonNull Rect other) {
565         left = Math.max(left, other.left);
566         top = Math.max(top, other.top);
567         right = Math.min(right, other.right);
568         bottom = Math.min(bottom, other.bottom);
569     }
570 
571     /**
572      * If rectangles a and b intersect, return true and set this rectangle to
573      * that intersection, otherwise return false and do not change this
574      * rectangle. No check is performed to see if either rectangle is empty.
575      * To just test for intersection, use intersects()
576      *
577      * @param a The first rectangle being intersected with
578      * @param b The second rectangle being intersected with
579      * @return true iff the two specified rectangles intersect. If they do, set
580      *              this rectangle to that intersection. If they do not, return
581      *              false and do not change this rectangle.
582      */
583     @CheckResult
setIntersect(@onNull Rect a, @NonNull Rect b)584     public boolean setIntersect(@NonNull Rect a, @NonNull Rect b) {
585         if (a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom) {
586             left = Math.max(a.left, b.left);
587             top = Math.max(a.top, b.top);
588             right = Math.min(a.right, b.right);
589             bottom = Math.min(a.bottom, b.bottom);
590             return true;
591         }
592         return false;
593     }
594 
595     /**
596      * Returns true if this rectangle intersects the specified rectangle.
597      * In no event is this rectangle modified. No check is performed to see
598      * if either rectangle is empty. To record the intersection, use intersect()
599      * or setIntersect().
600      *
601      * @param left The left side of the rectangle being tested for intersection
602      * @param top The top of the rectangle being tested for intersection
603      * @param right The right side of the rectangle being tested for
604      *              intersection
605      * @param bottom The bottom of the rectangle being tested for intersection
606      * @return true iff the specified rectangle intersects this rectangle. In
607      *              no event is this rectangle modified.
608      */
intersects(int left, int top, int right, int bottom)609     public boolean intersects(int left, int top, int right, int bottom) {
610         return this.left < right && left < this.right && this.top < bottom && top < this.bottom;
611     }
612 
613     /**
614      * Returns true iff the two specified rectangles intersect. In no event are
615      * either of the rectangles modified. To record the intersection,
616      * use {@link #intersect(Rect)} or {@link #setIntersect(Rect, Rect)}.
617      *
618      * @param a The first rectangle being tested for intersection
619      * @param b The second rectangle being tested for intersection
620      * @return true iff the two specified rectangles intersect. In no event are
621      *              either of the rectangles modified.
622      */
intersects(@onNull Rect a, @NonNull Rect b)623     public static boolean intersects(@NonNull Rect a, @NonNull Rect b) {
624         return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
625     }
626 
627     /**
628      * Update this Rect to enclose itself and the specified rectangle. If the
629      * specified rectangle is empty, nothing is done. If this rectangle is empty
630      * it is set to the specified rectangle.
631      *
632      * @param left The left edge being unioned with this rectangle
633      * @param top The top edge being unioned with this rectangle
634      * @param right The right edge being unioned with this rectangle
635      * @param bottom The bottom edge being unioned with this rectangle
636      */
union(int left, int top, int right, int bottom)637     public void union(int left, int top, int right, int bottom) {
638         if ((left < right) && (top < bottom)) {
639             if ((this.left < this.right) && (this.top < this.bottom)) {
640                 if (this.left > left) this.left = left;
641                 if (this.top > top) this.top = top;
642                 if (this.right < right) this.right = right;
643                 if (this.bottom < bottom) this.bottom = bottom;
644             } else {
645                 this.left = left;
646                 this.top = top;
647                 this.right = right;
648                 this.bottom = bottom;
649             }
650         }
651     }
652 
653     /**
654      * Update this Rect to enclose itself and the specified rectangle. If the
655      * specified rectangle is empty, nothing is done. If this rectangle is empty
656      * it is set to the specified rectangle.
657      *
658      * @param r The rectangle being unioned with this rectangle
659      */
union(@onNull Rect r)660     public void union(@NonNull Rect r) {
661         union(r.left, r.top, r.right, r.bottom);
662     }
663 
664     /**
665      * Update this Rect to enclose itself and the [x,y] coordinate. There is no
666      * check to see that this rectangle is non-empty.
667      *
668      * @param x The x coordinate of the point to add to the rectangle
669      * @param y The y coordinate of the point to add to the rectangle
670      */
union(int x, int y)671     public void union(int x, int y) {
672         if (x < left) {
673             left = x;
674         } else if (x > right) {
675             right = x;
676         }
677         if (y < top) {
678             top = y;
679         } else if (y > bottom) {
680             bottom = y;
681         }
682     }
683 
684     /**
685      * Swap top/bottom or left/right if there are flipped (i.e. left > right
686      * and/or top > bottom). This can be called if
687      * the edges are computed separately, and may have crossed over each other.
688      * If the edges are already correct (i.e. left <= right and top <= bottom)
689      * then nothing is done.
690      */
sort()691     public void sort() {
692         if (left > right) {
693             int temp = left;
694             left = right;
695             right = temp;
696         }
697         if (top > bottom) {
698             int temp = top;
699             top = bottom;
700             bottom = temp;
701         }
702     }
703 
704     /**
705      * Parcelable interface methods
706      */
707     @Override
describeContents()708     public int describeContents() {
709         return 0;
710     }
711 
712     /**
713      * Write this rectangle to the specified parcel. To restore a rectangle from
714      * a parcel, use readFromParcel()
715      * @param out The parcel to write the rectangle's coordinates into
716      */
717     @Override
writeToParcel(Parcel out, int flags)718     public void writeToParcel(Parcel out, int flags) {
719         out.writeInt(left);
720         out.writeInt(top);
721         out.writeInt(right);
722         out.writeInt(bottom);
723     }
724 
725     public static final @android.annotation.NonNull Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
726         /**
727          * Return a new rectangle from the data in the specified parcel.
728          */
729         @Override
730         public Rect createFromParcel(Parcel in) {
731             Rect r = new Rect();
732             r.readFromParcel(in);
733             return r;
734         }
735 
736         /**
737          * Return an array of rectangles of the specified size.
738          */
739         @Override
740         public Rect[] newArray(int size) {
741             return new Rect[size];
742         }
743     };
744 
745     /**
746      * Set the rectangle's coordinates from the data stored in the specified
747      * parcel. To write a rectangle to a parcel, call writeToParcel().
748      *
749      * @param in The parcel to read the rectangle's coordinates from
750      */
readFromParcel(@onNull Parcel in)751     public void readFromParcel(@NonNull Parcel in) {
752         left = in.readInt();
753         top = in.readInt();
754         right = in.readInt();
755         bottom = in.readInt();
756     }
757 
758     /**
759      * Scales up the rect by the given scale.
760      * @hide
761      */
762     @UnsupportedAppUsage
scale(float scale)763     public void scale(float scale) {
764         if (scale != 1.0f) {
765             left = (int) (left * scale + 0.5f);
766             top = (int) (top * scale + 0.5f);
767             right = (int) (right * scale + 0.5f);
768             bottom = (int) (bottom * scale + 0.5f);
769         }
770     }
771 
772 }
773