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 android.app.compat; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.content.pm.PackageInfo; 23 import android.os.Parcel; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.Objects; 28 29 /** 30 * An app compat override applied to a given package and change id pairing. 31 * 32 * A package override contains a list of version ranges with the desired boolean value of 33 * the override for the app in this version range. Ranges can be open ended in either direction. 34 * An instance of PackageOverride gets created via {@link Builder} and is immutable once created. 35 * 36 * @hide 37 */ 38 @SystemApi 39 public final class PackageOverride { 40 41 /** @hide */ 42 @IntDef({ 43 VALUE_UNDEFINED, 44 VALUE_ENABLED, 45 VALUE_DISABLED 46 }) 47 @Retention(RetentionPolicy.SOURCE) 48 public @interface EvaluatedOverride { 49 } 50 51 /** 52 * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that 53 * this PackageOverride does not define the value of the override for the given version. 54 * @hide 55 */ 56 public static final int VALUE_UNDEFINED = 0; 57 /** 58 * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that 59 * the override evaluates to {@code true} for the given version. 60 * @hide 61 */ 62 public static final int VALUE_ENABLED = 1; 63 /** 64 * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that 65 * the override evaluates to {@code fakse} for the given version. 66 * @hide 67 */ 68 public static final int VALUE_DISABLED = 2; 69 70 private final long mMinVersionCode; 71 private final long mMaxVersionCode; 72 private final boolean mEnabled; 73 PackageOverride(long minVersionCode, long maxVersionCode, boolean enabled)74 private PackageOverride(long minVersionCode, 75 long maxVersionCode, 76 boolean enabled) { 77 this.mMinVersionCode = minVersionCode; 78 this.mMaxVersionCode = maxVersionCode; 79 this.mEnabled = enabled; 80 } 81 82 /** 83 * Evaluate the override for the given {@code versionCode}. If no override is defined for 84 * the specified version code, {@link #VALUE_UNDEFINED} is returned. 85 * @hide 86 */ evaluate(long versionCode)87 public @EvaluatedOverride int evaluate(long versionCode) { 88 if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) { 89 return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; 90 } 91 return VALUE_UNDEFINED; 92 } 93 94 /** 95 * Evaluate the override independent of version code, i.e. only return an evaluated value if 96 * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned. 97 * @hide 98 */ evaluateForAllVersions()99 public int evaluateForAllVersions() { 100 if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { 101 return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; 102 } 103 return VALUE_UNDEFINED; 104 } 105 106 /** 107 * Returns the minimum APK version code the override applies to. 108 * 109 * @see PackageInfo#getLongVersionCode() 110 */ getMinVersionCode()111 public long getMinVersionCode() { 112 return mMinVersionCode; 113 } 114 115 /** 116 * Returns the maximum APK version code the override applies from. 117 * 118 * @see PackageInfo#getLongVersionCode() 119 */ getMaxVersionCode()120 public long getMaxVersionCode() { 121 return mMaxVersionCode; 122 } 123 124 /** Returns the enabled value for the override. */ isEnabled()125 public boolean isEnabled() { 126 return mEnabled; 127 } 128 129 /** @hide */ writeToParcel(Parcel dest)130 public void writeToParcel(Parcel dest) { 131 dest.writeLong(mMinVersionCode); 132 dest.writeLong(mMaxVersionCode); 133 dest.writeBoolean(mEnabled); 134 } 135 136 /** @hide */ createFromParcel(Parcel in)137 public static PackageOverride createFromParcel(Parcel in) { 138 return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean()); 139 } 140 141 /** @hide */ 142 @Override equals(Object o)143 public boolean equals(Object o) { 144 if (this == o) return true; 145 if (o == null || getClass() != o.getClass()) return false; 146 PackageOverride that = (PackageOverride) o; 147 return mMinVersionCode == that.mMinVersionCode && mMaxVersionCode == that.mMaxVersionCode 148 && mEnabled == that.mEnabled; 149 } 150 151 /** @hide */ 152 @Override hashCode()153 public int hashCode() { 154 return Objects.hash(mMinVersionCode, mMaxVersionCode, mEnabled); 155 } 156 157 /** @hide */ 158 @Override toString()159 public String toString() { 160 if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { 161 return Boolean.toString(mEnabled); 162 } 163 return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled); 164 } 165 166 /** 167 * Builder to construct a PackageOverride. 168 */ 169 public static final class Builder { 170 private long mMinVersionCode = Long.MIN_VALUE; 171 private long mMaxVersionCode = Long.MAX_VALUE; 172 private boolean mEnabled; 173 174 /** 175 * Sets the minimum APK version code the override should apply from. 176 * 177 * default value: {@code Long.MIN_VALUE}. 178 * 179 * @see PackageInfo#getLongVersionCode() 180 */ 181 @NonNull setMinVersionCode(long minVersionCode)182 public Builder setMinVersionCode(long minVersionCode) { 183 mMinVersionCode = minVersionCode; 184 return this; 185 } 186 187 /** 188 * Sets the maximum APK version code the override should apply to. 189 * 190 * default value: {@code Long.MAX_VALUE}. 191 * 192 * @see PackageInfo#getLongVersionCode() 193 */ 194 @NonNull setMaxVersionCode(long maxVersionCode)195 public Builder setMaxVersionCode(long maxVersionCode) { 196 mMaxVersionCode = maxVersionCode; 197 return this; 198 } 199 200 /** 201 * Sets whether the override should be enabled for the given version range. 202 * 203 * default value: {@code false}. 204 */ 205 @NonNull setEnabled(boolean enabled)206 public Builder setEnabled(boolean enabled) { 207 mEnabled = enabled; 208 return this; 209 } 210 211 /** 212 * Build the {@link PackageOverride}. 213 * 214 * @throws IllegalArgumentException if {@code minVersionCode} is larger than 215 * {@code maxVersionCode}. 216 */ 217 @NonNull build()218 public PackageOverride build() { 219 if (mMinVersionCode > mMaxVersionCode) { 220 throw new IllegalArgumentException("minVersionCode must not be larger than " 221 + "maxVersionCode"); 222 } 223 return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled); 224 } 225 }; 226 } 227