• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 android.car;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.car.annotation.ApiRequirements;
21 import android.car.annotation.ApiRequirements.CarVersion;
22 import android.car.annotation.ApiRequirements.PlatformVersion;
23 import android.os.Parcel;
24 import android.text.TextUtils;
25 
26 import java.util.Objects;
27 
28 /**
29  * Abstraction of Android APIs.
30  *
31  * <p>This class is used to represent a pair of major / minor API versions: the "major" version
32  * represents a "traditional" Android SDK release, while the "minor" is used to indicate incremental
33  * releases for that major.
34  *
35  * <p>This class is needed because the standard Android SDK API versioning only supports major
36  * releases, but {@code Car} APIs can now (starting on
37  * {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13}) be updated on minor releases
38  * as well.
39  *
40  * @param <T> implementation type
41  */
42 @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
43         minPlatformVersion = PlatformVersion.TIRAMISU_0)
44 public abstract class ApiVersion<T extends ApiVersion<?>> {
45 
46     /**
47      * When set, it's used on {@link #toString()} - useful for versions that are pre-defined
48      * (like {@code TIRAMISU_1}).
49      */
50     @Nullable
51     private final String mVersionName;
52 
53     private final int mMajorVersion;
54     private final int mMinorVersion;
55 
ApiVersion(int majorVersion, int minorVersion)56     ApiVersion(int majorVersion, int minorVersion) {
57         this(/* name= */ null, majorVersion, minorVersion);
58     }
59 
ApiVersion(String name, int majorVersion, int minorVersion)60     ApiVersion(String name, int majorVersion, int minorVersion) {
61         mVersionName = name;
62         mMajorVersion = majorVersion;
63         mMinorVersion = minorVersion;
64     }
65 
66     /**
67      * Checks if this API version meets the required version.
68      *
69      * @param requiredApiVersionMajor Required major version number.
70      * @param requiredApiVersionMinor Required minor version number.
71      * @return {@code true} if the {@link #getMajorVersion() major version} is newer than the
72      *         {@code requiredVersion}'s major or if the {@link #getMajorVersion() major version} is
73      *         the same as {@code requiredVersion}'s major with the {@link #getMinorVersion() minor
74      *         version} the same or newer than {@code requiredVersion}'s minor.
75      * @throws IllegalArgumentException if {@code requiredVersion} is not an instance of the same
76      *         class as this object.
77      */
78     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
79             minPlatformVersion = PlatformVersion.TIRAMISU_0)
isAtLeast(@onNull T requiredVersion)80     public final boolean isAtLeast(@NonNull T requiredVersion) {
81         Objects.requireNonNull(requiredVersion);
82 
83         if (!this.getClass().isInstance(requiredVersion)) {
84             throw new IllegalArgumentException("Cannot compare " + this.getClass().getName()
85                     + " against " + requiredVersion.getClass().getName());
86         }
87 
88         int requiredApiVersionMajor = requiredVersion.getMajorVersion();
89         int requiredApiVersionMinor = requiredVersion.getMinorVersion();
90 
91         return (mMajorVersion > requiredApiVersionMajor)
92                 || (mMajorVersion == requiredApiVersionMajor
93                         && mMinorVersion >= requiredApiVersionMinor);
94     }
95 
96     /**
97      * Gets the major version of the API represented by this object.
98      */
99     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
100             minPlatformVersion = PlatformVersion.TIRAMISU_0)
getMajorVersion()101     public final int getMajorVersion() {
102         return mMajorVersion;
103     }
104 
105     /**
106      * Gets the minor version change of API for the same {@link #getMajorVersion()}.
107      *
108      * <p>It will reset to {@code 0} whenever {@link #getMajorVersion()} is updated
109      * and will increase by {@code 1} if car builtin or other car platform part is changed with the
110      * same {@link #getMajorVersion()}.
111      *
112      * <p>Client should check this version to use APIs which were added in a minor-only version
113      * update.
114      */
115     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
116             minPlatformVersion = PlatformVersion.TIRAMISU_0)
getMinorVersion()117     public final int getMinorVersion() {
118         return mMinorVersion;
119     }
120 
121     /**
122      * @hide
123      */
124     @Override
equals(Object obj)125     public boolean equals(Object obj) {
126         if (this == obj) return true;
127         if (obj == null) return false;
128         if (getClass() != obj.getClass()) return false;
129         @SuppressWarnings("unchecked")
130         ApiVersion<T> other = (ApiVersion<T>) obj;
131         return (mMajorVersion == other.mMajorVersion) && (mMinorVersion == other.mMinorVersion);
132     }
133 
134     /**
135      * @hide
136      */
137     @Override
hashCode()138     public int hashCode() {
139         int prime = 31;
140         int result = 1;
141         result = prime * result + mMajorVersion;
142         result = prime * result + mMinorVersion;
143         return result;
144     }
145 
146     /**
147      * @hide
148      */
149     @Override
150     @NonNull
toString()151     public final String toString() {
152         StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
153         if (!TextUtils.isEmpty(mVersionName)) {
154             builder.append("name=").append(mVersionName).append(", ");
155         }
156         return builder
157                 .append("major=").append(mMajorVersion)
158                 .append(", minor=").append(mMinorVersion)
159                 .append(']').toString();
160     }
161 
162     /**
163      * @hide
164      */
165     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
166             minPlatformVersion = PlatformVersion.TIRAMISU_0)
writeToParcel(Parcel dest)167     protected void writeToParcel(Parcel dest) {
168         dest.writeString(mVersionName);
169         dest.writeInt(getMajorVersion());
170         dest.writeInt(getMinorVersion());
171     }
172 
173     /**
174      * @hide
175      */
176     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
177             minPlatformVersion = PlatformVersion.TIRAMISU_0)
readFromParcel(Parcel source, ApiVersionFactory<T> factory)178     protected static <T extends ApiVersion<?>> T readFromParcel(Parcel source,
179             ApiVersionFactory<T> factory) {
180         String name = source.readString();
181         int major = source.readInt();
182         int minor = source.readInt();
183         return factory.newInstance(name, major, minor);
184     }
185 
186     /**
187      * @hide
188      */
189     interface ApiVersionFactory<T extends ApiVersion<?>> {
190         @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
191                 minPlatformVersion = PlatformVersion.TIRAMISU_0)
newInstance(String name, int major, int minor)192         T newInstance(String name, int major, int minor);
193     }
194 }
195