blob: 9c4f80b39b7d60bb6d203e7d1c78da61839dadbd [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.car;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
import java.util.Objects;
/**
* Abstraction of Android APIs.
*
* <p>This class is used to represent a pair of major / minor API versions: the "major" version
* represents a "traditional" Android SDK release, while the "minor" is used to indicate incremental
* releases for that major.
*
* <p>This class is needed because the standard Android SDK API versioning only supports major
* releases, but {@code Car} APIs can now (starting on
* {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13}) be updated on minor releases
* as well.
*
* @param <T> implementation type
*/
public abstract class ApiVersion<T extends ApiVersion<?>> {
/**
* When set, it's used on {@link #toString()} - useful for versions that are pre-defined
* (like {@code TIRAMISU_1}).
*/
@Nullable
private final String mVersionName;
private final int mMajorVersion;
private final int mMinorVersion;
ApiVersion(int majorVersion, int minorVersion) {
this(/* name= */ null, majorVersion, minorVersion);
}
ApiVersion(String name, int majorVersion, int minorVersion) {
mVersionName = name;
mMajorVersion = majorVersion;
mMinorVersion = minorVersion;
}
/**
* Checks if this API version meets the required version.
*
* @param requiredVersion required major and minor version number
* @return {@code true} if the {@link #getMajorVersion() major version} is newer than the
* {@code requiredVersion}'s major or if the {@link #getMajorVersion() major version} is
* the same as {@code requiredVersion}'s major with the {@link #getMinorVersion() minor
* version} the same or newer than {@code requiredVersion}'s minor
* @throws IllegalArgumentException if {@code requiredVersion} is not an instance of the same
* class as this object
*/
public final boolean isAtLeast(@NonNull T requiredVersion) {
Objects.requireNonNull(requiredVersion);
if (!this.getClass().isInstance(requiredVersion)) {
throw new IllegalArgumentException("Cannot compare " + this.getClass().getName()
+ " against " + requiredVersion.getClass().getName());
}
int requiredApiVersionMajor = requiredVersion.getMajorVersion();
int requiredApiVersionMinor = requiredVersion.getMinorVersion();
return (mMajorVersion > requiredApiVersionMajor)
|| (mMajorVersion == requiredApiVersionMajor
&& mMinorVersion >= requiredApiVersionMinor);
}
/**
* Gets the major version of the API represented by this object.
*/
public final int getMajorVersion() {
return mMajorVersion;
}
/**
* Gets the minor version change of API for the same {@link #getMajorVersion()}.
*
* <p>It will reset to {@code 0} whenever {@link #getMajorVersion()} is updated
* and will increase by {@code 1} if car builtin or other car platform part is changed with the
* same {@link #getMajorVersion()}.
*
* <p>Client should check this version to use APIs which were added in a minor-only version
* update.
*/
public final int getMinorVersion() {
return mMinorVersion;
}
/**
* @hide
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
@SuppressWarnings("unchecked")
ApiVersion<T> other = (ApiVersion<T>) obj;
return (mMajorVersion == other.mMajorVersion) && (mMinorVersion == other.mMinorVersion);
}
/**
* @hide
*/
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + mMajorVersion;
result = prime * result + mMinorVersion;
return result;
}
/**
* @hide
*/
@Override
@NonNull
public final String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
if (!TextUtils.isEmpty(mVersionName)) {
builder.append("name=").append(mVersionName).append(", ");
}
return builder
.append("major=").append(mMajorVersion)
.append(", minor=").append(mMinorVersion)
.append(']').toString();
}
/**
* @hide
*/
protected void writeToParcel(Parcel dest) {
dest.writeString(mVersionName);
dest.writeInt(getMajorVersion());
dest.writeInt(getMinorVersion());
}
/**
* @hide
*/
protected static <T extends ApiVersion<?>> T readFromParcel(Parcel source,
ApiVersionFactory<T> factory) {
String name = source.readString();
int major = source.readInt();
int minor = source.readInt();
return factory.newInstance(name, major, minor);
}
/**
* @hide
*/
interface ApiVersionFactory<T extends ApiVersion<?>> {
T newInstance(String name, int major, int minor);
}
}