• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.android.apps.common.testing.accessibility.framework.replacements;
16 
17 import static com.google.common.base.Preconditions.checkNotNull;
18 import static java.lang.Math.max;
19 import static java.lang.Math.min;
20 
21 import com.google.android.apps.common.testing.accessibility.framework.uielement.proto.AndroidFrameworkProtos.RectProto;
22 import com.google.errorprone.annotations.Immutable;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25 import org.checkerframework.checker.nullness.qual.Nullable;
26 
27 /** Used as a local immutable replacement for Android's {@link android.graphics.Rect} */
28 @Immutable
29 public final class Rect {
30 
31   public static final Rect EMPTY = new Rect(0, 0, 0, 0);
32 
33   private static final Pattern FLATTENED_PATTERN =
34       Pattern.compile("(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");
35 
36   private final int left;
37   private final int top;
38   private final int right;
39   private final int bottom;
40 
Rect(int left, int top, int right, int bottom)41   public Rect(int left, int top, int right, int bottom) {
42     // Ensure coordinate ordering is sensible
43     this.left = min(left, right);
44     this.top = min(top, bottom);
45     this.right = max(left, right);
46     this.bottom = max(top, bottom);
47   }
48 
Rect(RectProto rectProto)49   public Rect(RectProto rectProto) {
50     this(rectProto.getLeft(), rectProto.getTop(), rectProto.getRight(), rectProto.getBottom());
51   }
52 
53   /** See {@link android.graphics.Rect#left} */
getLeft()54   public final int getLeft() {
55     return left;
56   }
57 
58   /** See {@link android.graphics.Rect#top} */
getTop()59   public final int getTop() {
60     return top;
61   }
62 
63   /** See {@link android.graphics.Rect#right} */
getRight()64   public final int getRight() {
65     return right;
66   }
67 
68   /** See {@link android.graphics.Rect#bottom} */
getBottom()69   public final int getBottom() {
70     return bottom;
71   }
72 
73   /** See {@link android.graphics.Rect#width()} */
getWidth()74   public final int getWidth() {
75     return right - left;
76   }
77 
78   /** See {@link android.graphics.Rect#height()} */
getHeight()79   public final int getHeight() {
80     return bottom - top;
81   }
82 
area()83   public final int area() {
84     return getWidth() * getHeight();
85   }
86 
87   /** See {@link android.graphics.Rect#contains(android.graphics.Rect)} */
contains(Rect r)88   public boolean contains(Rect r) {
89     return !isEmpty()
90         && (this.left <= r.left)
91         && (this.top <= r.top)
92         && (this.right >= r.right)
93         && (this.bottom >= r.bottom);
94   }
95 
96   /** See {@link android.graphics.Rect#contains(int, int)} */
contains(int x, int y)97   public boolean contains(int x, int y) {
98     return !isEmpty() && x >= left && x < right && y >= top && y < bottom;
99   }
100 
101   /** See {@link android.graphics.Rect#isEmpty()} */
isEmpty()102   public boolean isEmpty() {
103     return (left == right) || (top == bottom);
104   }
105 
106   /**
107    * Returns a {@link Rect} which encloses this rectangle and the specified rectangle. If the
108    * specified rectangle is empty, return {@code this}. If this rectangle is empty, return the
109    * specified rectangle.
110    *
111    * <p>See {@link android.graphics.Rect#union(android.graphics.Rect)}
112    *
113    * @param r The rectangle being unioned with this rectangle
114    */
union(Rect r)115   public Rect union(Rect r) {
116     return isEmpty() ? r : union(r.left, r.top, r.right, r.bottom);
117   }
118 
119   /**
120    * Returns a {@link Rect} which encloses this rectangle and the specified rectangle. If the
121    * specified rectangle is empty, return {@code this}. If this rectangle is empty, return the
122    * specified rectangle.
123    *
124    * <p>See {@link android.graphics.Rect#union(int, int, int, int)}
125    *
126    * @param left The left edge being unioned with this rectangle
127    * @param top The top edge being unioned with this rectangle
128    * @param right The right edge being unioned with this rectangle
129    * @param bottom The bottom edge being unioned with this rectangle
130    */
union(int left, int top, int right, int bottom)131   public Rect union(int left, int top, int right, int bottom) {
132     if ((right <= left) || (bottom <= top)) {
133       return this;
134     }
135 
136     if (isEmpty()) {
137       return new Rect(left, top, right, bottom);
138     } else {
139       return new Rect(
140           min(left, this.left),
141           min(top, this.top),
142           max(right, this.right),
143           max(bottom, this.bottom));
144     }
145   }
146 
147   /**
148    * Returns a {@link Rect} that represents the intersection of this rectangle and the specific
149    * rectangle. If there is no intersection, an empty rectangle is returned.
150    *
151    * @param r The rectangle being intersected with this rectangle
152    */
intersect(Rect r)153   public Rect intersect(Rect r) {
154     if (!Rect.intersects(this, r)) {
155       return Rect.EMPTY;
156     }
157 
158     return new Rect(
159         max(left, r.getLeft()),
160         max(top, r.getTop()),
161         min(right, r.getRight()),
162         min(bottom, r.getBottom()));
163   }
164 
toProto()165   public RectProto toProto() {
166     return RectProto.newBuilder()
167         .setLeft(left)
168         .setTop(top)
169         .setRight(right)
170         .setBottom(bottom)
171         .build();
172   }
173 
174   @Override
equals(@ullable Object o)175   public boolean equals(@Nullable Object o) {
176     if (this == o) {
177       return true;
178     }
179 
180     if (o == null || Rect.class != o.getClass()) {
181       return false;
182     }
183 
184     Rect r = (Rect) o;
185     return ((left == r.left) && (top == r.top) && (right == r.right) && (bottom == r.bottom));
186   }
187 
188   @Override
hashCode()189   public int hashCode() {
190     int result = left;
191     result = 31 * result + top;
192     result = 31 * result + right;
193     result = 31 * result + bottom;
194     return result;
195   }
196 
197   @Override
toString()198   public String toString() {
199     return "Rect(" + left + ", " + top + " - " + right + ", " + bottom + ")";
200   }
201 
202   /** See {@link android.graphics.Rect#toShortString()} */
toShortString()203   public String toShortString() {
204     return "[" + left + ',' + top + "][" + right + ',' + bottom + ']';
205   }
206 
207   /** See {@link android.graphics.Rect#flattenToString()} */
flattenToString()208   public String flattenToString() {
209     return Integer.toString(left) + ' ' + top + ' ' + right + ' ' + bottom;
210   }
211 
212   /** See {@link android.graphics.Rect#unflattenFromString()} */
unflattenFromString(@ullable String str)213   public static @Nullable Rect unflattenFromString(@Nullable String str) {
214     if (TextUtils.isEmpty(str)) {
215       return null;
216     }
217 
218     Matcher matcher = FLATTENED_PATTERN.matcher(str);
219     if (matcher.matches()) {
220       return new Rect(
221           Integer.parseInt(checkNotNull(matcher.group(1))),
222           Integer.parseInt(checkNotNull(matcher.group(2))),
223           Integer.parseInt(checkNotNull(matcher.group(3))),
224           Integer.parseInt(checkNotNull(matcher.group(4))));
225     }
226     return null;
227   }
228 
229   /** See {@link android.graphics.Rect#intersects(android.graphics.Rect, android.graphics.Rect)} */
intersects(Rect a, Rect b)230   public static boolean intersects(Rect a, Rect b) {
231     return (a.top < b.bottom) && (b.top < a.bottom) && (a.left < b.right) && (b.left < a.right);
232   }
233 }
234