1 /* 2 * Copyright (C) 2011 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 com.android.sdkuilib.internal.repository.sdkman2; 18 19 import com.android.sdklib.internal.repository.Archive; 20 import com.android.sdklib.internal.repository.IPackageVersion; 21 import com.android.sdklib.internal.repository.Package; 22 import com.android.sdklib.internal.repository.Package.UpdateInfo; 23 import com.android.sdklib.internal.repository.SdkSource; 24 25 /** 26 * A {@link PkgItem} represents one main {@link Package} combined with its state 27 * and an optional update package. 28 * <p/> 29 * The main package is final and cannot change since it's what "defines" this PkgItem. 30 * The state or update package can change later. 31 */ 32 public class PkgItem implements Comparable<PkgItem> { 33 private final PkgState mState; 34 private final Package mMainPkg; 35 private Package mUpdatePkg; 36 private boolean mChecked; 37 38 /** 39 * The state of the a given {@link PkgItem}, that is the relationship between 40 * a given remote package and the local repository. 41 */ 42 public enum PkgState { 43 /** 44 * Package is locally installed and may or may not have an update. 45 */ 46 INSTALLED, 47 48 /** 49 * There's a new package available on the remote site that isn't installed locally. 50 */ 51 NEW 52 } 53 54 /** 55 * Create a new {@link PkgItem} for this main package. 56 * The main package is final and cannot change since it's what "defines" this PkgItem. 57 * The state or update package can change later. 58 */ PkgItem(Package mainPkg, PkgState state)59 public PkgItem(Package mainPkg, PkgState state) { 60 mMainPkg = mainPkg; 61 mState = state; 62 assert mMainPkg != null; 63 } 64 isObsolete()65 public boolean isObsolete() { 66 return mMainPkg.isObsolete(); 67 } 68 isChecked()69 public boolean isChecked() { 70 return mChecked; 71 } 72 setChecked(boolean checked)73 public void setChecked(boolean checked) { 74 mChecked = checked; 75 } 76 getUpdatePkg()77 public Package getUpdatePkg() { 78 return mUpdatePkg; 79 } 80 hasUpdatePkg()81 public boolean hasUpdatePkg() { 82 return mUpdatePkg != null; 83 } 84 getName()85 public String getName() { 86 return mMainPkg.getListDescription(); 87 } 88 getRevision()89 public int getRevision() { 90 return mMainPkg.getRevision(); 91 } 92 getDescription()93 public String getDescription() { 94 return mMainPkg.getDescription(); 95 } 96 getMainPackage()97 public Package getMainPackage() { 98 return mMainPkg; 99 } 100 getState()101 public PkgState getState() { 102 return mState; 103 } 104 getSource()105 public SdkSource getSource() { 106 return mMainPkg.getParentSource(); 107 } 108 getApi()109 public int getApi() { 110 return mMainPkg instanceof IPackageVersion ? 111 ((IPackageVersion) mMainPkg).getVersion().getApiLevel() : 112 -1; 113 } 114 getArchives()115 public Archive[] getArchives() { 116 return mMainPkg.getArchives(); 117 } 118 compareTo(PkgItem pkg)119 public int compareTo(PkgItem pkg) { 120 return getMainPackage().compareTo(pkg.getMainPackage()); 121 } 122 123 /** 124 * Returns true if this package or its updating packages contains 125 * the exact given archive. 126 * Important: This compares object references, not object equality. 127 */ hasArchive(Archive archive)128 public boolean hasArchive(Archive archive) { 129 if (mMainPkg.hasArchive(archive)) { 130 return true; 131 } 132 if (mUpdatePkg != null && mUpdatePkg.hasArchive(archive)) { 133 return true; 134 } 135 return false; 136 } 137 138 /** 139 * Returns true if the main package has at least one archive 140 * compatible with the current platform. 141 */ hasCompatibleArchive()142 public boolean hasCompatibleArchive() { 143 return mMainPkg.hasCompatibleArchive(); 144 } 145 146 /** 147 * Checks whether the main packages are of the same type and are 148 * not an update of each other. 149 */ isSameMainPackageAs(Package pkg)150 public boolean isSameMainPackageAs(Package pkg) { 151 if (mMainPkg.canBeUpdatedBy(pkg) == UpdateInfo.NOT_UPDATE) { 152 // package revision numbers must match 153 return mMainPkg.getRevision() == pkg.getRevision(); 154 } 155 return false; 156 } 157 158 /** 159 * Checks whether too {@link PkgItem} are the same. 160 * This checks both items have the same state, both main package are similar 161 * and that they have the same updating packages. 162 */ isSameItemAs(PkgItem item)163 public boolean isSameItemAs(PkgItem item) { 164 if (this == item) { 165 return true; 166 } 167 boolean same = this.mState == item.mState; 168 if (same) { 169 same = isSameMainPackageAs(item.getMainPackage()); 170 } 171 172 if (same) { 173 // check updating packages are the same 174 Package p1 = this.mUpdatePkg; 175 Package p2 = item.getUpdatePkg(); 176 same = (p1 == p2) || (p1 == null && p2 == null) || (p1 != null && p2 != null); 177 178 if (same && p1 != null) { 179 same = p1.canBeUpdatedBy(p2) == UpdateInfo.NOT_UPDATE; 180 } 181 } 182 183 return same; 184 } 185 186 /** 187 * Equality is defined as {@link #isSameItemAs(PkgItem)}: state, main package 188 * and update package must be the similar. 189 */ 190 @Override equals(Object obj)191 public boolean equals(Object obj) { 192 return (obj instanceof PkgItem) && this.isSameItemAs((PkgItem) obj); 193 } 194 195 @Override hashCode()196 public int hashCode() { 197 final int prime = 31; 198 int result = 1; 199 result = prime * result + ((mState == null) ? 0 : mState.hashCode()); 200 result = prime * result + ((mMainPkg == null) ? 0 : mMainPkg.hashCode()); 201 result = prime * result + ((mUpdatePkg == null) ? 0 : mUpdatePkg.hashCode()); 202 return result; 203 } 204 205 /** 206 * Check whether the 'pkg' argument is an update for this package. 207 * If it is, record it as an updating package. 208 * If there's already an updating package, only keep the most recent update. 209 * Returns true if it is update (even if there was already an update and this 210 * ended up not being the most recent), false if incompatible or not an update. 211 * 212 * This should only be used for installed packages. 213 */ mergeUpdate(Package pkg)214 public boolean mergeUpdate(Package pkg) { 215 if (mUpdatePkg == pkg) { 216 return true; 217 } 218 if (mMainPkg.canBeUpdatedBy(pkg) == UpdateInfo.UPDATE) { 219 if (mUpdatePkg == null) { 220 mUpdatePkg = pkg; 221 } else if (mUpdatePkg.canBeUpdatedBy(pkg) == UpdateInfo.UPDATE) { 222 // If we have more than one, keep only the most recent update 223 mUpdatePkg = pkg; 224 } 225 return true; 226 } 227 228 return false; 229 } 230 removeUpdate()231 public void removeUpdate() { 232 mUpdatePkg = null; 233 } 234 235 /** Returns a string representation of this item, useful when debugging. */ 236 @Override toString()237 public String toString() { 238 StringBuilder sb = new StringBuilder(); 239 sb.append('<'); 240 241 if (mChecked) { 242 sb.append(" * "); //$NON-NLS-1$ 243 } 244 245 sb.append(mState.toString()); 246 247 if (mMainPkg != null) { 248 sb.append(", pkg:"); //$NON-NLS-1$ 249 sb.append(mMainPkg.toString()); 250 } 251 252 if (mUpdatePkg != null) { 253 sb.append(", updated by:"); //$NON-NLS-1$ 254 sb.append(mUpdatePkg.toString()); 255 } 256 257 sb.append('>'); 258 return sb.toString(); 259 } 260 261 } 262