1 /* 2 * Copyright (C) 2015 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.content.om; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 /** 28 * Immutable overlay information about a package. All PackageInfos that 29 * represent an overlay package will have a corresponding OverlayInfo. 30 * 31 * @hide 32 */ 33 public final class OverlayInfo implements Parcelable { 34 35 @IntDef(prefix = "STATE_", value = { 36 STATE_UNKNOWN, 37 STATE_MISSING_TARGET, 38 STATE_NO_IDMAP, 39 STATE_DISABLED, 40 STATE_ENABLED, 41 STATE_ENABLED_STATIC, 42 STATE_TARGET_UPGRADING, 43 STATE_OVERLAY_UPGRADING, 44 }) 45 @Retention(RetentionPolicy.SOURCE) 46 public @interface State {} 47 48 /** 49 * An internal state used as the initial state of an overlay. OverlayInfo 50 * objects exposed outside the {@link 51 * com.android.server.om.OverlayManagerService} should never have this 52 * state. 53 */ 54 public static final int STATE_UNKNOWN = -1; 55 56 /** 57 * The target package of the overlay is not installed. The overlay cannot be enabled. 58 */ 59 public static final int STATE_MISSING_TARGET = 0; 60 61 /** 62 * Creation of idmap file failed (e.g. no matching resources). The overlay 63 * cannot be enabled. 64 */ 65 public static final int STATE_NO_IDMAP = 1; 66 67 /** 68 * The overlay is currently disabled. It can be enabled. 69 * 70 * @see IOverlayManager#setEnabled 71 */ 72 public static final int STATE_DISABLED = 2; 73 74 /** 75 * The overlay is currently enabled. It can be disabled. 76 * 77 * @see IOverlayManager#setEnabled 78 */ 79 public static final int STATE_ENABLED = 3; 80 81 /** 82 * The target package is currently being upgraded; the state will change 83 * once the package installation has finished. 84 */ 85 public static final int STATE_TARGET_UPGRADING = 4; 86 87 /** 88 * The overlay package is currently being upgraded; the state will change 89 * once the package installation has finished. 90 */ 91 public static final int STATE_OVERLAY_UPGRADING = 5; 92 93 /** 94 * The overlay package is currently enabled because it is marked as 95 * 'static'. It cannot be disabled but will change state if for instance 96 * its target is uninstalled. 97 */ 98 public static final int STATE_ENABLED_STATIC = 6; 99 100 /** 101 * Overlay category: theme. 102 * <p> 103 * Change how Android (including the status bar, dialogs, ...) looks. 104 */ 105 public static final String CATEGORY_THEME = "android.theme"; 106 107 /** 108 * Package name of the overlay package 109 */ 110 public final String packageName; 111 112 /** 113 * Package name of the target package 114 */ 115 public final String targetPackageName; 116 117 /** 118 * Category of the overlay package 119 */ 120 public final String category; 121 122 /** 123 * Full path to the base APK for this overlay package 124 */ 125 public final String baseCodePath; 126 127 /** 128 * The state of this OverlayInfo as defined by the STATE_* constants in this class. 129 */ 130 public final @State int state; 131 132 /** 133 * User handle for which this overlay applies 134 */ 135 public final int userId; 136 137 /** 138 * Priority as read from the manifest. Used if isStatic is true. Not 139 * intended to be exposed to 3rd party. 140 * 141 * @hide 142 */ 143 public final int priority; 144 145 /** 146 * isStatic as read from the manifest. If true, the overlay is 147 * unconditionally loaded and cannot be unloaded. Not intended to be 148 * exposed to 3rd party. 149 * 150 * @hide 151 */ 152 public final boolean isStatic; 153 154 /** 155 * Create a new OverlayInfo based on source with an updated state. 156 * 157 * @param source the source OverlayInfo to base the new instance on 158 * @param state the new state for the source OverlayInfo 159 */ OverlayInfo(@onNull OverlayInfo source, @State int state)160 public OverlayInfo(@NonNull OverlayInfo source, @State int state) { 161 this(source.packageName, source.targetPackageName, source.category, source.baseCodePath, 162 state, source.userId, source.priority, source.isStatic); 163 } 164 OverlayInfo(@onNull String packageName, @NonNull String targetPackageName, @NonNull String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isStatic)165 public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, 166 @NonNull String category, @NonNull String baseCodePath, int state, int userId, 167 int priority, boolean isStatic) { 168 this.packageName = packageName; 169 this.targetPackageName = targetPackageName; 170 this.category = category; 171 this.baseCodePath = baseCodePath; 172 this.state = state; 173 this.userId = userId; 174 this.priority = priority; 175 this.isStatic = isStatic; 176 ensureValidState(); 177 } 178 OverlayInfo(Parcel source)179 public OverlayInfo(Parcel source) { 180 packageName = source.readString(); 181 targetPackageName = source.readString(); 182 category = source.readString(); 183 baseCodePath = source.readString(); 184 state = source.readInt(); 185 userId = source.readInt(); 186 priority = source.readInt(); 187 isStatic = source.readBoolean(); 188 ensureValidState(); 189 } 190 ensureValidState()191 private void ensureValidState() { 192 if (packageName == null) { 193 throw new IllegalArgumentException("packageName must not be null"); 194 } 195 if (targetPackageName == null) { 196 throw new IllegalArgumentException("targetPackageName must not be null"); 197 } 198 if (baseCodePath == null) { 199 throw new IllegalArgumentException("baseCodePath must not be null"); 200 } 201 switch (state) { 202 case STATE_UNKNOWN: 203 case STATE_MISSING_TARGET: 204 case STATE_NO_IDMAP: 205 case STATE_DISABLED: 206 case STATE_ENABLED: 207 case STATE_ENABLED_STATIC: 208 case STATE_TARGET_UPGRADING: 209 case STATE_OVERLAY_UPGRADING: 210 break; 211 default: 212 throw new IllegalArgumentException("State " + state + " is not a valid state"); 213 } 214 } 215 216 @Override describeContents()217 public int describeContents() { 218 return 0; 219 } 220 221 @Override writeToParcel(Parcel dest, int flags)222 public void writeToParcel(Parcel dest, int flags) { 223 dest.writeString(packageName); 224 dest.writeString(targetPackageName); 225 dest.writeString(category); 226 dest.writeString(baseCodePath); 227 dest.writeInt(state); 228 dest.writeInt(userId); 229 dest.writeInt(priority); 230 dest.writeBoolean(isStatic); 231 } 232 233 public static final Parcelable.Creator<OverlayInfo> CREATOR = 234 new Parcelable.Creator<OverlayInfo>() { 235 @Override 236 public OverlayInfo createFromParcel(Parcel source) { 237 return new OverlayInfo(source); 238 } 239 240 @Override 241 public OverlayInfo[] newArray(int size) { 242 return new OverlayInfo[size]; 243 } 244 }; 245 246 /** 247 * Return true if this overlay is enabled, i.e. should be used to overlay 248 * the resources in the target package. 249 * 250 * Disabled overlay packages are installed but are currently not in use. 251 * 252 * @return true if the overlay is enabled, else false. 253 */ isEnabled()254 public boolean isEnabled() { 255 switch (state) { 256 case STATE_ENABLED: 257 case STATE_ENABLED_STATIC: 258 return true; 259 default: 260 return false; 261 } 262 } 263 264 /** 265 * Translate a state to a human readable string. Only intended for 266 * debugging purposes. 267 * 268 * @return a human readable String representing the state. 269 */ stateToString(@tate int state)270 public static String stateToString(@State int state) { 271 switch (state) { 272 case STATE_UNKNOWN: 273 return "STATE_UNKNOWN"; 274 case STATE_MISSING_TARGET: 275 return "STATE_MISSING_TARGET"; 276 case STATE_NO_IDMAP: 277 return "STATE_NO_IDMAP"; 278 case STATE_DISABLED: 279 return "STATE_DISABLED"; 280 case STATE_ENABLED: 281 return "STATE_ENABLED"; 282 case STATE_ENABLED_STATIC: 283 return "STATE_ENABLED_STATIC"; 284 case STATE_TARGET_UPGRADING: 285 return "STATE_TARGET_UPGRADING"; 286 case STATE_OVERLAY_UPGRADING: 287 return "STATE_OVERLAY_UPGRADING"; 288 default: 289 return "<unknown state>"; 290 } 291 } 292 293 @Override hashCode()294 public int hashCode() { 295 final int prime = 31; 296 int result = 1; 297 result = prime * result + userId; 298 result = prime * result + state; 299 result = prime * result + ((packageName == null) ? 0 : packageName.hashCode()); 300 result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); 301 result = prime * result + ((category == null) ? 0 : category.hashCode()); 302 result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode()); 303 return result; 304 } 305 306 @Override equals(Object obj)307 public boolean equals(Object obj) { 308 if (this == obj) { 309 return true; 310 } 311 if (obj == null) { 312 return false; 313 } 314 if (getClass() != obj.getClass()) { 315 return false; 316 } 317 OverlayInfo other = (OverlayInfo) obj; 318 if (userId != other.userId) { 319 return false; 320 } 321 if (state != other.state) { 322 return false; 323 } 324 if (!packageName.equals(other.packageName)) { 325 return false; 326 } 327 if (!targetPackageName.equals(other.targetPackageName)) { 328 return false; 329 } 330 if (!category.equals(other.category)) { 331 return false; 332 } 333 if (!baseCodePath.equals(other.baseCodePath)) { 334 return false; 335 } 336 return true; 337 } 338 339 @Override toString()340 public String toString() { 341 return "OverlayInfo { overlay=" + packageName + ", target=" + targetPackageName + ", state=" 342 + state + " (" + stateToString(state) + "), userId=" + userId + " }"; 343 } 344 } 345