• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.adservices.shared.testing;
17 
18 import com.google.common.annotations.VisibleForTesting;
19 
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Objects;
23 
24 /** Abstraction for Android SDK levels (so it can be used both on device and host side tests). */
25 public final class AndroidSdk {
26 
27     private static final Logger sLogger = new Logger(DynamicLogger.getInstance(), AndroidSdk.class);
28 
29     /** Android version {@code RVC}. */
30     public static final int RVC = 30;
31 
32     /** Android version {@code SC}. */
33     public static final int SC = 31;
34 
35     /** Android version {@code SC_V2}. */
36     public static final int SC_V2 = 32;
37 
38     /** Android version {@code TM}. */
39     public static final int TM = 33;
40 
41     /** Android version {@code UC}. */
42     public static final int UDC = 34;
43 
44     /** Android version {@code VIC}. */
45     public static final int VIC = 35;
46 
47     /** Android version {@code BAK}. */
48     public static final int BAK = 36;
49 
50     /** Android version for unreleased builds}. */
51     public static final int CUR_DEVELOPMENT = 10_000; // Build.CUR_DEVELOPMENT.CUR_DEVELOPMENT
52 
53     /**
54      * Convenience for ranges that are "less than T" (for example {@code
55      * RequiresSdkRange(atMost=PRE_T)}), as S had 2 APIs (31 and 32)
56      */
57     public static final int PRE_T = SC_V2;
58 
59     // TODO(b/324919960): make it package-protected again or make sure it's unit tested.
60     /** Represents a specific SDK level. */
61     public enum Level {
62         ANY(Integer.MIN_VALUE),
63         DEV(CUR_DEVELOPMENT),
64         R(RVC),
65         S(SC),
66         S2(SC_V2),
67         T(TM),
68         U(UDC),
69         V(VIC),
70         B(BAK);
71 
72         private final int mLevel;
73 
Level(int level)74         Level(int level) {
75             mLevel = level;
76         }
77 
78         // TODO(b/324919960): make it package-protected again or make sure it's unit tested.
79         /** Checks if SDK is at least the given level. */
isAtLeast(Level level)80         public boolean isAtLeast(Level level) {
81             return mLevel >= level.mLevel;
82         }
83 
84         // TODO(b/324919960): make it package-protected again or make sure it's unit tested.
85         /** Gets the numeric representation of the SDK level (like {@code 33}). */
getLevel()86         public int getLevel() {
87             return mLevel;
88         }
89 
90         /** Gets the level abstraction for the given level). */
forLevel(int level)91         public static Level forLevel(int level) {
92             switch (level) {
93                 case CUR_DEVELOPMENT:
94                     return DEV;
95                 case RVC:
96                     return R;
97                 case SC:
98                     return S;
99                 case SC_V2:
100                     return S2;
101                 case TM:
102                     return T;
103                 case UDC:
104                     return U;
105                 case VIC:
106                     return V;
107                 case BAK:
108                     return B;
109             }
110             if (level > BAK) {
111                 sLogger.e(
112                         "WARNING: Level.forLevel() called with unsupported / unreleased level (%d);"
113                                 + " returning DEV (%d)",
114                         level, DEV.mLevel);
115                 return DEV;
116             }
117             throw new IllegalArgumentException("Unsupported level: " + level);
118         }
119     }
120 
121     // TODO(b/324919960): make it package-protected again or make sure it's unit tested.
122     /** Represents a range of Android API levels. */
123     public static final class Range {
124         // TODO(b/324919960): make them package-protected again or make sure it's unit tested.
125         public static final int NO_MIN = Integer.MIN_VALUE;
126         public static final int NO_MAX = Integer.MAX_VALUE;
127 
128         private final int mMinLevel;
129         private final int mMaxLevel;
130 
Range(int minLevel, int maxLevel)131         private Range(int minLevel, int maxLevel) {
132             if (minLevel > maxLevel || minLevel == NO_MAX || maxLevel == NO_MIN) {
133                 throw new IllegalArgumentException(
134                         "maxLevel ("
135                                 + maxLevel
136                                 + ") must equal or higher than minLevel ("
137                                 + minLevel
138                                 + ")");
139             }
140             mMinLevel = minLevel;
141             mMaxLevel = maxLevel;
142         }
143 
144         /** Gets a range without an upper boundary. */
forAtLeast(int level)145         public static Range forAtLeast(int level) {
146             return new Range(/* minLevel= */ level, NO_MAX);
147         }
148 
149         /** Gets a range without a lower boundary. */
forAtMost(int level)150         public static Range forAtMost(int level) {
151             return new Range(NO_MIN, /* maxLevel= */ level);
152         }
153 
154         /** Gets a range for the specific levels. */
forRange(int minLevel, int maxLevel)155         public static Range forRange(int minLevel, int maxLevel) {
156             return new Range(minLevel, maxLevel);
157         }
158 
159         /** Gets a range for a specific level. */
forExactly(int level)160         public static Range forExactly(int level) {
161             return new Range(/* minLevel= */ level, /* maxLevel= */ level);
162         }
163 
164         /** Gets a range that includes any level. */
forAnyLevel()165         public static Range forAnyLevel() {
166             return new Range(NO_MIN, NO_MAX);
167         }
168 
169         /** Checks if the given level fits this range (inclusive). */
isInRange(int level)170         public boolean isInRange(int level) {
171             return level >= mMinLevel && level <= mMaxLevel;
172         }
173 
174         @VisibleForTesting
merge(Range... ranges)175         static Range merge(Range... ranges) {
176             return merge(Arrays.asList(ranges));
177         }
178 
merge(Collection<Range> ranges)179         static Range merge(Collection<Range> ranges) {
180             Objects.requireNonNull(ranges, "ranges cannot be null");
181             if (ranges.isEmpty()) {
182                 throw new IllegalArgumentException("ranges cannot be empty");
183             }
184             int minRange = NO_MIN;
185             int maxRange = NO_MAX;
186             for (Range range : ranges) {
187                 if (range == null) {
188                     throw new IllegalArgumentException("ranges cannot have null range: " + ranges);
189                 }
190                 minRange = Math.max(minRange, range.mMinLevel);
191                 maxRange = Math.min(maxRange, range.mMaxLevel);
192             }
193             return forRange(minRange, maxRange);
194         }
195 
196         @Override
hashCode()197         public int hashCode() {
198             return Objects.hash(mMaxLevel, mMinLevel);
199         }
200 
201         @Override
equals(Object obj)202         public boolean equals(Object obj) {
203             if (this == obj) return true;
204             if (obj == null) return false;
205             if (getClass() != obj.getClass()) return false;
206             Range other = (Range) obj;
207             return mMaxLevel == other.mMaxLevel && mMinLevel == other.mMinLevel;
208         }
209 
210         @Override
toString()211         public String toString() {
212             StringBuilder builder = new StringBuilder("AndroidSdkRange[minLevel=");
213             if (mMinLevel == NO_MIN) {
214                 builder.append("OPEN");
215             } else {
216                 builder.append(mMinLevel);
217             }
218             builder.append(", maxLevel=");
219             if (mMaxLevel == NO_MAX) {
220                 builder.append("OPEN");
221             } else {
222                 builder.append(mMaxLevel);
223             }
224             return builder.append(']').toString();
225         }
226     }
227 
AndroidSdk()228     private AndroidSdk() {
229         throw new UnsupportedOperationException();
230     }
231 }
232