1 /*
2  * Copyright (C) 2021 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 com.android.bedstead.nene.utils;
18 
19 import android.os.Build;
20 
21 import java.lang.reflect.Field;
22 
23 /** SDK Version checks. */
24 public final class Versions {
25 
26     /** Any version. */
27     public static final int ANY = -1;
28 
29     private static final String DEVELOPMENT_CODENAME = "S";
30 
Versions()31     private Versions() {
32 
33     }
34 
35     /**
36      * Throw a {@link UnsupportedOperationException} if the minimum version requirement is not met.
37      */
requireMinimumVersion(int min)38     public static void requireMinimumVersion(int min) {
39         if (!meetsSdkVersionRequirements(min, ANY)) {
40             throw new UnsupportedOperationException(
41                     "Thie feature is only available on "
42                             + versionToLetter(min)
43                             + "+ (currently " + Build.VERSION.CODENAME + ")");
44         }
45     }
46 
versionToLetter(int version)47     private static String versionToLetter(int version) {
48         for (Field field : Build.VERSION_CODES.class.getFields()) {
49             if (!java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
50                 continue;
51             }
52             if (!field.getType().equals(int.class)) {
53                 continue;
54             }
55             try {
56                 int fieldValue = (int) field.get(null);
57 
58                 if (fieldValue == version) {
59                     return field.getName();
60                 }
61             } catch (IllegalAccessException e) {
62                 // Couldn't access this variable - ignore
63             }
64         }
65 
66         throw new IllegalStateException("Could not find version with code " + version);
67     }
68 
69     /**
70      * {@code true} if the minimum version requirement is met.
71      */
meetsMinimumSdkVersionRequirement(int min)72     public static boolean meetsMinimumSdkVersionRequirement(int min) {
73         return meetsSdkVersionRequirements(min, ANY);
74     }
75 
76     /**
77      * {@code true} if the minimum and maximum version requirements are met.
78      *
79      * <p>Use {@link #ANY} to accept any version.
80      */
meetsSdkVersionRequirements(int min, int max)81     public static boolean meetsSdkVersionRequirements(int min, int max) {
82         if (min != ANY) {
83             if (min == Build.VERSION_CODES.CUR_DEVELOPMENT) {
84                 if (!Build.VERSION.CODENAME.equals(DEVELOPMENT_CODENAME)) {
85                     return false;
86                 }
87             } else if (min > Build.VERSION.SDK_INT) {
88                 return false;
89             }
90         }
91 
92         if (max != ANY
93                 && max != Build.VERSION_CODES.CUR_DEVELOPMENT
94                 && max < Build.VERSION.SDK_INT) {
95             return false;
96         }
97 
98         return true;
99     }
100 }
101