/* * Copyright (C) 2021 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.app.compat; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.pm.PackageInfo; import android.os.Parcel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * An app compat override applied to a given package and change id pairing. * * A package override contains a list of version ranges with the desired boolean value of * the override for the app in this version range. Ranges can be open ended in either direction. * An instance of PackageOverride gets created via {@link Builder} and is immutable once created. * * @hide */ @SystemApi public final class PackageOverride { /** @hide */ @IntDef({ VALUE_UNDEFINED, VALUE_ENABLED, VALUE_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface EvaluatedOverride { } /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * this PackageOverride does not define the value of the override for the given version. * @hide */ public static final int VALUE_UNDEFINED = 0; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code true} for the given version. * @hide */ public static final int VALUE_ENABLED = 1; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code fakse} for the given version. * @hide */ public static final int VALUE_DISABLED = 2; private final long mMinVersionCode; private final long mMaxVersionCode; private final boolean mEnabled; private PackageOverride(long minVersionCode, long maxVersionCode, boolean enabled) { this.mMinVersionCode = minVersionCode; this.mMaxVersionCode = maxVersionCode; this.mEnabled = enabled; } /** * Evaluate the override for the given {@code versionCode}. If no override is defined for * the specified version code, {@link #VALUE_UNDEFINED} is returned. * @hide */ public @EvaluatedOverride int evaluate(long versionCode) { if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** * Evaluate the override independent of version code, i.e. only return an evaluated value if * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned. * @hide */ public int evaluateForAllVersions() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** * Returns the minimum APK version code the override applies to. * * @see PackageInfo#getLongVersionCode() */ public long getMinVersionCode() { return mMinVersionCode; } /** * Returns the maximum APK version code the override applies from. * * @see PackageInfo#getLongVersionCode() */ public long getMaxVersionCode() { return mMaxVersionCode; } /** Returns the enabled value for the override. */ public boolean isEnabled() { return mEnabled; } /** @hide */ public void writeToParcel(Parcel dest) { dest.writeLong(mMinVersionCode); dest.writeLong(mMaxVersionCode); dest.writeBoolean(mEnabled); } /** @hide */ public static PackageOverride createFromParcel(Parcel in) { return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean()); } /** @hide */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PackageOverride that = (PackageOverride) o; return mMinVersionCode == that.mMinVersionCode && mMaxVersionCode == that.mMaxVersionCode && mEnabled == that.mEnabled; } /** @hide */ @Override public int hashCode() { return Objects.hash(mMinVersionCode, mMaxVersionCode, mEnabled); } /** @hide */ @Override public String toString() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return Boolean.toString(mEnabled); } return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled); } /** * Builder to construct a PackageOverride. */ public static final class Builder { private long mMinVersionCode = Long.MIN_VALUE; private long mMaxVersionCode = Long.MAX_VALUE; private boolean mEnabled; /** * Sets the minimum APK version code the override should apply from. * * default value: {@code Long.MIN_VALUE}. * * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMinVersionCode(long minVersionCode) { mMinVersionCode = minVersionCode; return this; } /** * Sets the maximum APK version code the override should apply to. * * default value: {@code Long.MAX_VALUE}. * * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMaxVersionCode(long maxVersionCode) { mMaxVersionCode = maxVersionCode; return this; } /** * Sets whether the override should be enabled for the given version range. * * default value: {@code false}. */ @NonNull public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } /** * Build the {@link PackageOverride}. * * @throws IllegalArgumentException if {@code minVersionCode} is larger than * {@code maxVersionCode}. */ @NonNull public PackageOverride build() { if (mMinVersionCode > mMaxVersionCode) { throw new IllegalArgumentException("minVersionCode must not be larger than " + "maxVersionCode"); } return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled); } }; }