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.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.annotation.UnsupportedAppUsage; 24 import android.annotation.UserIdInt; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.Objects; 31 32 /** 33 * Immutable overlay information about a package. All PackageInfos that 34 * represent an overlay package will have a corresponding OverlayInfo. 35 * 36 * @hide 37 */ 38 @SystemApi 39 public final class OverlayInfo implements Parcelable { 40 41 /** @hide */ 42 @IntDef(prefix = "STATE_", value = { 43 STATE_UNKNOWN, 44 STATE_MISSING_TARGET, 45 STATE_NO_IDMAP, 46 STATE_DISABLED, 47 STATE_ENABLED, 48 STATE_ENABLED_STATIC, 49 // @Deprecated STATE_TARGET_IS_BEING_REPLACED, 50 STATE_OVERLAY_IS_BEING_REPLACED, 51 }) 52 /** @hide */ 53 @Retention(RetentionPolicy.SOURCE) 54 public @interface State {} 55 56 /** 57 * An internal state used as the initial state of an overlay. OverlayInfo 58 * objects exposed outside the {@link 59 * com.android.server.om.OverlayManagerService} should never have this 60 * state. 61 * 62 * @hide 63 */ 64 public static final int STATE_UNKNOWN = -1; 65 66 /** 67 * The target package of the overlay is not installed. The overlay cannot be enabled. 68 * 69 * @hide 70 */ 71 public static final int STATE_MISSING_TARGET = 0; 72 73 /** 74 * Creation of idmap file failed (e.g. no matching resources). The overlay 75 * cannot be enabled. 76 * 77 * @hide 78 */ 79 public static final int STATE_NO_IDMAP = 1; 80 81 /** 82 * The overlay is currently disabled. It can be enabled. 83 * 84 * @see IOverlayManager#setEnabled 85 * @hide 86 */ 87 public static final int STATE_DISABLED = 2; 88 89 /** 90 * The overlay is currently enabled. It can be disabled. 91 * 92 * @see IOverlayManager#setEnabled 93 * @hide 94 */ 95 public static final int STATE_ENABLED = 3; 96 97 /** 98 * The target package is currently being upgraded or downgraded; the state 99 * will change once the package installation has finished. 100 * @hide 101 * 102 * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled, 103 * where an update is propagated when nothing has changed. Can occur during --dont-kill 104 * installs when code and resources are hot swapped and the Activity should not be relaunched. 105 * In all other cases, the process and therefore Activity is killed, so the state loop is 106 * irrelevant. 107 */ 108 @Deprecated 109 public static final int STATE_TARGET_IS_BEING_REPLACED = 4; 110 111 /** 112 * The overlay package is currently being upgraded or downgraded; the state 113 * will change once the package installation has finished. 114 * @hide 115 */ 116 public static final int STATE_OVERLAY_IS_BEING_REPLACED = 5; 117 118 /** 119 * The overlay package is currently enabled because it is marked as 120 * 'static'. It cannot be disabled but will change state if for instance 121 * its target is uninstalled. 122 * @hide 123 */ 124 public static final int STATE_ENABLED_STATIC = 6; 125 126 /** 127 * Overlay category: theme. 128 * <p> 129 * Change how Android (including the status bar, dialogs, ...) looks. 130 * 131 * @hide 132 */ 133 public static final String CATEGORY_THEME = "android.theme"; 134 135 /** 136 * Package name of the overlay package 137 * 138 * @hide 139 */ 140 public final String packageName; 141 142 /** 143 * Package name of the target package 144 * 145 * @hide 146 */ 147 public final String targetPackageName; 148 149 /** 150 * Name of the target overlayable declaration. 151 * 152 * @hide 153 */ 154 public final String targetOverlayableName; 155 156 /** 157 * Category of the overlay package 158 * 159 * @hide 160 */ 161 public final String category; 162 163 /** 164 * Full path to the base APK for this overlay package 165 * @hide 166 */ 167 public final String baseCodePath; 168 169 /** 170 * The state of this OverlayInfo as defined by the STATE_* constants in this class. 171 * @hide 172 */ 173 @UnsupportedAppUsage 174 public final @State int state; 175 176 /** 177 * User handle for which this overlay applies 178 * @hide 179 */ 180 public final int userId; 181 182 /** 183 * Priority as read from the manifest. Used if isStatic is true. Not 184 * intended to be exposed to 3rd party. 185 * 186 * @hide 187 */ 188 public final int priority; 189 190 /** 191 * isStatic as read from the manifest. If true, the overlay is 192 * unconditionally loaded and cannot be unloaded. Not intended to be 193 * exposed to 3rd party. 194 * 195 * @hide 196 */ 197 public final boolean isStatic; 198 199 /** 200 * Create a new OverlayInfo based on source with an updated state. 201 * 202 * @param source the source OverlayInfo to base the new instance on 203 * @param state the new state for the source OverlayInfo 204 * 205 * @hide 206 */ OverlayInfo(@onNull OverlayInfo source, @State int state)207 public OverlayInfo(@NonNull OverlayInfo source, @State int state) { 208 this(source.packageName, source.targetPackageName, source.targetOverlayableName, 209 source.category, source.baseCodePath, state, source.userId, source.priority, 210 source.isStatic); 211 } 212 213 /** @hide */ OverlayInfo(@onNull String packageName, @NonNull String targetPackageName, @Nullable String targetOverlayableName, @Nullable String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isStatic)214 public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, 215 @Nullable String targetOverlayableName, @Nullable String category, 216 @NonNull String baseCodePath, int state, int userId, 217 int priority, boolean isStatic) { 218 this.packageName = packageName; 219 this.targetPackageName = targetPackageName; 220 this.targetOverlayableName = targetOverlayableName; 221 this.category = category; 222 this.baseCodePath = baseCodePath; 223 this.state = state; 224 this.userId = userId; 225 this.priority = priority; 226 this.isStatic = isStatic; 227 ensureValidState(); 228 } 229 230 /** @hide */ OverlayInfo(Parcel source)231 public OverlayInfo(Parcel source) { 232 packageName = source.readString(); 233 targetPackageName = source.readString(); 234 targetOverlayableName = source.readString(); 235 category = source.readString(); 236 baseCodePath = source.readString(); 237 state = source.readInt(); 238 userId = source.readInt(); 239 priority = source.readInt(); 240 isStatic = source.readBoolean(); 241 ensureValidState(); 242 } 243 244 /** 245 * Returns package name of the current overlay. 246 * @hide 247 */ 248 @SystemApi 249 @NonNull getPackageName()250 public String getPackageName() { 251 return packageName; 252 } 253 254 /** 255 * Returns the target package name of the current overlay. 256 * @hide 257 */ 258 @SystemApi 259 @NonNull getTargetPackageName()260 public String getTargetPackageName() { 261 return targetPackageName; 262 } 263 264 /** 265 * Returns the category of the current overlay. 266 * @hide\ 267 */ 268 @SystemApi 269 @Nullable getCategory()270 public String getCategory() { 271 return category; 272 } 273 274 /** 275 * Returns user handle for which this overlay applies to. 276 * @hide 277 */ 278 @SystemApi 279 @UserIdInt getUserId()280 public int getUserId() { 281 return userId; 282 } 283 284 /** 285 * Returns name of the target overlayable declaration. 286 * @hide 287 */ 288 @SystemApi 289 @Nullable getTargetOverlayableName()290 public String getTargetOverlayableName() { 291 return targetOverlayableName; 292 } 293 ensureValidState()294 private void ensureValidState() { 295 if (packageName == null) { 296 throw new IllegalArgumentException("packageName must not be null"); 297 } 298 if (targetPackageName == null) { 299 throw new IllegalArgumentException("targetPackageName must not be null"); 300 } 301 if (baseCodePath == null) { 302 throw new IllegalArgumentException("baseCodePath must not be null"); 303 } 304 switch (state) { 305 case STATE_UNKNOWN: 306 case STATE_MISSING_TARGET: 307 case STATE_NO_IDMAP: 308 case STATE_DISABLED: 309 case STATE_ENABLED: 310 case STATE_ENABLED_STATIC: 311 case STATE_TARGET_IS_BEING_REPLACED: 312 case STATE_OVERLAY_IS_BEING_REPLACED: 313 break; 314 default: 315 throw new IllegalArgumentException("State " + state + " is not a valid state"); 316 } 317 } 318 319 @Override describeContents()320 public int describeContents() { 321 return 0; 322 } 323 324 @Override writeToParcel(Parcel dest, int flags)325 public void writeToParcel(Parcel dest, int flags) { 326 dest.writeString(packageName); 327 dest.writeString(targetPackageName); 328 dest.writeString(targetOverlayableName); 329 dest.writeString(category); 330 dest.writeString(baseCodePath); 331 dest.writeInt(state); 332 dest.writeInt(userId); 333 dest.writeInt(priority); 334 dest.writeBoolean(isStatic); 335 } 336 337 public static final @android.annotation.NonNull Parcelable.Creator<OverlayInfo> CREATOR = 338 new Parcelable.Creator<OverlayInfo>() { 339 @Override 340 public OverlayInfo createFromParcel(Parcel source) { 341 return new OverlayInfo(source); 342 } 343 344 @Override 345 public OverlayInfo[] newArray(int size) { 346 return new OverlayInfo[size]; 347 } 348 }; 349 350 /** 351 * Return true if this overlay is enabled, i.e. should be used to overlay 352 * the resources in the target package. 353 * 354 * Disabled overlay packages are installed but are currently not in use. 355 * 356 * @return true if the overlay is enabled, else false. 357 * @hide 358 */ 359 @SystemApi isEnabled()360 public boolean isEnabled() { 361 switch (state) { 362 case STATE_ENABLED: 363 case STATE_ENABLED_STATIC: 364 return true; 365 default: 366 return false; 367 } 368 } 369 370 /** 371 * Translate a state to a human readable string. Only intended for 372 * debugging purposes. 373 * 374 * @return a human readable String representing the state. 375 * @hide 376 */ stateToString(@tate int state)377 public static String stateToString(@State int state) { 378 switch (state) { 379 case STATE_UNKNOWN: 380 return "STATE_UNKNOWN"; 381 case STATE_MISSING_TARGET: 382 return "STATE_MISSING_TARGET"; 383 case STATE_NO_IDMAP: 384 return "STATE_NO_IDMAP"; 385 case STATE_DISABLED: 386 return "STATE_DISABLED"; 387 case STATE_ENABLED: 388 return "STATE_ENABLED"; 389 case STATE_ENABLED_STATIC: 390 return "STATE_ENABLED_STATIC"; 391 case STATE_TARGET_IS_BEING_REPLACED: 392 return "STATE_TARGET_IS_BEING_REPLACED"; 393 case STATE_OVERLAY_IS_BEING_REPLACED: 394 return "STATE_OVERLAY_IS_BEING_REPLACED"; 395 default: 396 return "<unknown state>"; 397 } 398 } 399 400 @Override hashCode()401 public int hashCode() { 402 final int prime = 31; 403 int result = 1; 404 result = prime * result + userId; 405 result = prime * result + state; 406 result = prime * result + ((packageName == null) ? 0 : packageName.hashCode()); 407 result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); 408 result = prime * result + ((targetOverlayableName == null) ? 0 409 : targetOverlayableName.hashCode()); 410 result = prime * result + ((category == null) ? 0 : category.hashCode()); 411 result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode()); 412 return result; 413 } 414 415 @Override equals(Object obj)416 public boolean equals(Object obj) { 417 if (this == obj) { 418 return true; 419 } 420 if (obj == null) { 421 return false; 422 } 423 if (getClass() != obj.getClass()) { 424 return false; 425 } 426 OverlayInfo other = (OverlayInfo) obj; 427 if (userId != other.userId) { 428 return false; 429 } 430 if (state != other.state) { 431 return false; 432 } 433 if (!packageName.equals(other.packageName)) { 434 return false; 435 } 436 if (!targetPackageName.equals(other.targetPackageName)) { 437 return false; 438 } 439 if (!Objects.equals(targetOverlayableName, other.targetOverlayableName)) { 440 return false; 441 } 442 if (!Objects.equals(category, other.category)) { 443 return false; 444 } 445 if (!baseCodePath.equals(other.baseCodePath)) { 446 return false; 447 } 448 return true; 449 } 450 451 @Override toString()452 public String toString() { 453 return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName 454 + ((targetOverlayableName == null) ? "" 455 : ", targetOverlayable=" + targetOverlayableName) 456 + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }"; 457 } 458 } 459