diff options
author | Raphael <raphael@google.com> | 2011-11-01 13:59:46 -0700 |
---|---|---|
committer | Raphael <raphael@google.com> | 2011-11-01 22:58:30 -0700 |
commit | 0e7626245014c961d3272ae8fa401e09bec6ee30 (patch) | |
tree | 5c4d351cca6aed8c685bb8b7d5c56a530811efaf /sdkmanager/libs/sdkuilib/src | |
parent | dca8a2a8e492cda47c61a8196f9c41cd6508394b (diff) | |
download | sdk-0e7626245014c961d3272ae8fa401e09bec6ee30.zip sdk-0e7626245014c961d3272ae8fa401e09bec6ee30.tar.gz sdk-0e7626245014c961d3272ae8fa401e09bec6ee30.tar.bz2 |
SdkManager: rework pkg diff to avoid duplicates
Change-Id: Iad1576ec4ca03213679aabb97328bcf9c0f590eb
Diffstat (limited to 'sdkmanager/libs/sdkuilib/src')
3 files changed, 211 insertions, 405 deletions
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogic.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogic.java index 5b6a157..beef56f 100755 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogic.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogic.java @@ -26,21 +26,18 @@ import com.android.sdklib.internal.repository.PlatformToolPackage; import com.android.sdklib.internal.repository.SdkSource; import com.android.sdklib.internal.repository.SystemImagePackage; import com.android.sdklib.internal.repository.ToolPackage; -import com.android.sdklib.internal.repository.Package.UpdateInfo; -import com.android.sdklib.repository.SdkRepoConstants; import com.android.sdklib.util.SparseArray; import com.android.sdkuilib.internal.repository.UpdaterData; import com.android.sdkuilib.internal.repository.sdkman2.PkgItem.PkgState; -import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -247,7 +244,10 @@ class PackagesDiffLogic { */ abstract class UpdateOp { private final Set<SdkSource> mVisitedSources = new HashSet<SdkSource>(); - protected final List<PkgCategory> mCategories = new ArrayList<PkgCategory>(); + private final List<PkgCategory> mCategories = new ArrayList<PkgCategory>(); + private final Set<PkgCategory> mCatsToRemove = new HashSet<PkgCategory>(); + private final Set<PkgItem> mItemsToRemove = new HashSet<PkgItem>(); + private final Map<Package, PkgItem> mUpdatesToRemove = new HashMap<Package, PkgItem>(); /** Removes all internal state. */ public void clear() { @@ -276,18 +276,23 @@ class PackagesDiffLogic { * items and/or adjust the category name. */ public abstract void postCategoryItemsChanged(); - /** Add the new package or merge it as an update or does nothing if this package - * is already part of the category items. - * Returns true if the category item list has changed. */ - public abstract boolean mergeNewPackage(Package newPackage, PkgCategory cat); - public void updateStart() { mVisitedSources.clear(); // Note that default categories are created after the unused ones so that // the callback can decide whether they should be marked as unused or not. + mCatsToRemove.clear(); + mItemsToRemove.clear(); + mUpdatesToRemove.clear(); for (PkgCategory cat : mCategories) { - cat.setUnused(true); + mCatsToRemove.add(cat); + List<PkgItem> items = cat.getItems(); + mItemsToRemove.addAll(items); + for (PkgItem item : items) { + if (item.hasUpdatePkg()) { + mUpdatesToRemove.put(item.getUpdatePkg(), item); + } + } } addDefaultCategories(); @@ -307,34 +312,57 @@ class PackagesDiffLogic { public boolean updateEnd() { boolean hasChanged = false; - // Remove unused categories + // Remove unused categories & items at the end of the update synchronized (mCategories) { - for (Iterator<PkgCategory> catIt = mCategories.iterator(); catIt.hasNext(); ) { - PkgCategory cat = catIt.next(); - if (cat.isUnused()) { - catIt.remove(); + for (PkgCategory unusedCat : mCatsToRemove) { + if (mCategories.remove(unusedCat)) { hasChanged = true; - continue; } + } + } - // Remove all *remote* items which obsolete source we have not been visited. - // This detects packages which have disappeared from a remote source during an - // update and removes from the current list. - // Locally installed item are never removed. - for (Iterator<PkgItem> itemIt = cat.getItems().iterator(); - itemIt.hasNext(); ) { - PkgItem item = itemIt.next(); - if (item.getState() == PkgState.NEW && - !mVisitedSources.contains(item.getSource())) { - itemIt.remove(); - hasChanged = true; - } + for (PkgCategory cat : mCategories) { + for (Iterator<PkgItem> itemIt = cat.getItems().iterator(); itemIt.hasNext(); ) { + PkgItem item = itemIt.next(); + if (mItemsToRemove.contains(item)) { + itemIt.remove(); + } else if (item.hasUpdatePkg() && + mUpdatesToRemove.containsKey(item.getUpdatePkg())) { + item.removeUpdate(); } } } + + mCatsToRemove.clear(); + mItemsToRemove.clear(); + mUpdatesToRemove.clear(); + return hasChanged; } + public boolean isKeep(PkgItem item) { + return !mItemsToRemove.contains(item); + } + + public void keep(Package pkg) { + mUpdatesToRemove.remove(pkg); + } + + public void keep(PkgItem item) { + mItemsToRemove.remove(item); + } + + public void keep(PkgCategory cat) { + mCatsToRemove.remove(cat); + } + + public void dontKeep(PkgItem item) { + mItemsToRemove.add(item); + } + + public void dontKeep(PkgCategory cat) { + mCatsToRemove.add(cat); + } } private final UpdateOpApi mOpApi = new UpdateOpApi(); @@ -389,80 +417,49 @@ class PackagesDiffLogic { return displayIsSortByApi ? apiListChanged : sourceListChanged; } + /** Process all local packages. Returns true if something changed. */ private boolean processLocals(UpdateOp op, Package[] packages) { boolean hasChanged = false; - Set<Package> newPackages = new HashSet<Package>(Arrays.asList(packages)); - Set<Package> unusedPackages = new HashSet<Package>(newPackages); - - assert newPackages.size() == packages.length; - - // Upgrade NEW items to INSTALLED for any local package we already know about. - // We can't just change the state of the NEW item to INSTALLED, we also need its - // installed package/archive information and so we swap them in-place in the items list. - - for (PkgCategory cat : op.getCategories()) { - List<PkgItem> items = cat.getItems(); - for (int i = 0; i < items.size(); i++) { - PkgItem item = items.get(i); - - if (item.hasUpdatePkg()) { - Package newPkg = setContainsLocalPackage(newPackages, item.getUpdatePkg()); - if (newPkg != null) { - // This item has an update package that is now installed. - PkgItem installed = new PkgItem(newPkg, PkgState.INSTALLED); - removePackageFromSet(unusedPackages, newPkg); - item.removeUpdate(); - items.add(installed); - cat.setUnused(false); - hasChanged = true; - } - } - - Package newPkg = setContainsLocalPackage(newPackages, item.getMainPackage()); - if (newPkg != null) { - removePackageFromSet(unusedPackages, newPkg); - cat.setUnused(false); - if (item.getState() == PkgState.NEW) { - // This item has a main package that is now installed. - replace(items, i, new PkgItem(newPkg, PkgState.INSTALLED)); - hasChanged = true; + List<PkgCategory> cats = op.getCategories(); + Set<PkgItem> keep = new HashSet<PkgItem>(); + + // For all locally installed packages, check they are either listed + // as installed or create new installed items for them. + + nextPkg: for (Package localPkg : packages) { + // Check to see if we already have the exact same package + // (type & revision) marked as installed. + for (PkgCategory cat : cats) { + for (PkgItem currItem : cat.getItems()) { + if (currItem.getState() == PkgState.INSTALLED && + currItem.isSameMainPackageAs(localPkg)) { + // This package is already listed as installed. + op.keep(currItem); + op.keep(cat); + keep.add(currItem); + continue nextPkg; } } } - } - // Remove INSTALLED items if their package isn't listed anymore in locals - for (PkgCategory cat : op.getCategories()) { - List<PkgItem> items = cat.getItems(); - for (int i = 0; i < items.size(); i++) { - PkgItem item = items.get(i); - - if (item.getState() == PkgState.INSTALLED) { - Package newPkg = setContainsLocalPackage(newPackages, item.getMainPackage()); - if (newPkg == null) { - items.remove(i--); - hasChanged = true; - } - } - } + // If not found, create a new installed package item + keep.add(addNewItem(op, localPkg, PkgState.INSTALLED)); + hasChanged = true; } - // Create new 'installed' items for any local package we haven't processed yet - for (Package newPackage : unusedPackages) { - Object catKey = op.getCategoryKey(newPackage); - PkgCategory cat = findCurrentCategory(op.getCategories(), catKey); + // Remove installed items that we don't want to keep anymore. They would normally be + // cleanup up in UpdateOp.updateEnd(); however it's easier to remove them before we + // run processSource() to avoid merging updates in items that would be removed later. - if (cat == null) { - // This is a new category. Create it and add it to the list. - cat = op.createCategory(catKey); - op.getCategories().add(cat); - op.sortCategoryList(); + for (PkgCategory cat : cats) { + for (Iterator<PkgItem> itemIt = cat.getItems().iterator(); itemIt.hasNext(); ) { + PkgItem item = itemIt.next(); + if (item.getState() == PkgState.INSTALLED && !keep.contains(item)) { + itemIt.remove(); + hasChanged = true; + } } - - cat.getItems().add(new PkgItem(newPackage, PkgState.INSTALLED)); - cat.setUnused(false); - hasChanged = true; } if (hasChanged) { @@ -472,175 +469,81 @@ class PackagesDiffLogic { return hasChanged; } - /** - * Replaces the item at {@code index} in {@code list} with the new {@code obj} element. - * This uses {@link ArrayList#set(int, Object)} if possible, remove+add otherwise. - * - * @return The old item at the same index position. - * @throws IndexOutOfBoundsException if index out of range (index < 0 || index >= size()). - */ - private <T> T replace(List<T> list, int index, T obj) { - if (list instanceof ArrayList<?>) { - return ((ArrayList<T>) list).set(index, obj); - } else { - T old = list.remove(index); - list.add(index, obj); - return old; - } - } - - /** - * Checks whether the {@code newPackages} set contains a package that is the - * same as {@code pkgToFind}. - * This is based on Package being the same from an install point of view rather than - * pure object equality. - * @return The matching package from the {@code newPackages} set or null if not found. - */ - private Package setContainsLocalPackage(Collection<Package> newPackages, Package pkgToFind) { - // Most of the time, local packages don't have the exact same hash code - // as new ones since the objects are similar but not exactly the same, - // for example their installed OS path cannot match (by definition) so - // their hash code do not match when used with Set.contains(). - - for (Package newPkg : newPackages) { - // Two packages are the same if they are compatible types, - // do not update each other and have the same revision number. - if (pkgToFind.canBeUpdatedBy(newPkg) == UpdateInfo.NOT_UPDATE && - newPkg.getRevision() == pkgToFind.getRevision()) { - return newPkg; - } - } - - return null; - } - - /** - * Removes the given package from the set. - * This is based on Package being the same from an install point of view rather than - * pure object equality. - */ - private void removePackageFromSet(Collection<Package> packages, Package pkgToFind) { - // First try to remove the package based on its hash code. This can fail - // for a variety of reasons, as explained in setContainsLocalPackage(). - if (packages.remove(pkgToFind)) { - return; - } - - for (Package pkg : packages) { - // Two packages are the same if they are compatible types, - // or not updates of each other and have the same revision number. - if (pkgToFind.canBeUpdatedBy(pkg) == UpdateInfo.NOT_UPDATE && - pkg.getRevision() == pkgToFind.getRevision()) { - packages.remove(pkg); - // Implementation detail: we can get away with using Collection.remove() - // whilst in the for iterator because we return right away (otherwise the - // iterator would complain the collection just changed.) - return; - } - } - } - - /** - * Removes any package from the set that is equal or lesser than {@code pkgToFind}. - * This is based on Package being the same from an install point of view rather than - * pure object equality. - * </p> - * This is a slight variation on {@link #removePackageFromSet(Collection, Package)} - * where we remove from the set any package that is similar to {@code pkgToFind} - * and has either the same revision number or a <em>lesser</em> revision number. - * An example of this use-case is there's an installed local package in rev 5 - * (that is the pkgToFind) and there's a remote package in rev 3 (in the package list), - * in which case we 'forget' the rev 3 package even exists. - */ - private void removePackageOrLesserFromSet(Collection<Package> packages, Package pkgToFind) { - for (Iterator<Package> it = packages.iterator(); it.hasNext(); ) { - Package pkg = it.next(); - - // Two packages are the same if they are compatible types, - // or not updates of each other and have the same revision number. - if (pkgToFind.canBeUpdatedBy(pkg) == UpdateInfo.NOT_UPDATE && - pkg.getRevision() <= pkgToFind.getRevision()) { - it.remove(); - } - } - } - /** Process all remote packages. Returns true if something changed. */ private boolean processSource(UpdateOp op, SdkSource source, Package[] packages) { boolean hasChanged = false; - // Note: unusedPackages must respect the original packages order. It can't be a set. - List<Package> unusedPackages = new ArrayList<Package>(Arrays.asList(packages)); - Set<Package> newPackages = new HashSet<Package>(unusedPackages); - - assert source != null; - assert newPackages.size() == packages.length; - - // Remove any items or updates that are no longer in the source's packages - for (PkgCategory cat : op.getCategories()) { - List<PkgItem> items = cat.getItems(); - for (int i = 0; i < items.size(); i++) { - PkgItem item = items.get(i); - - // Does the source provide this kind of package? - // FIXME. This is a crude workaround for bug 5508174; the - // diff logic has a larger issue, this is merely a quick fix. - // The downside is that if a remote source stops offering a given - // package type (e.g. a specific addon), it will still show up as - // available until the sdk manager is restarted. - boolean foundSame = false; - for (Package pkg : packages) { - if (pkg.sameItemAs(item.getMainPackage())) { - foundSame = true; - break; - } - } - if (!foundSame) { - continue; - } - - // Try to prune current items that are no longer on the remote site. - // Installed items have been dealt with the local source, so only - // change new items here. - if (item.getState() == PkgState.NEW) { - Package newPkg = setContainsLocalPackage(newPackages, item.getMainPackage()); - if (newPkg == null) { - // This package is no longer part of the source. - items.remove(i--); - hasChanged = true; - continue; - } - } + List<PkgCategory> cats = op.getCategories(); + + nextPkg: for (Package newPkg : packages) { + for (PkgCategory cat : cats) { + for (PkgState state : PkgState.values()) { + for (Iterator<PkgItem> currItemIt = cat.getItems().iterator(); + currItemIt.hasNext(); ) { + PkgItem currItem = currItemIt.next(); + // We need to merge with installed items first. When installing + // the diff will have both the new and the installed item and we + // need to merge with the installed one before the new one. + if (currItem.getState() != state) { + continue; + } + // Only process current items if they represent the same item (but + // with a different revision number) than the new package. + Package mainPkg = currItem.getMainPackage(); + if (!mainPkg.sameItemAs(newPkg)) { + continue; + } - cat.setUnused(false); - removePackageOrLesserFromSet(unusedPackages, item.getMainPackage()); + // Check to see if we already have the exact same package + // (type & revision) marked as main or update package. + if (currItem.isSameMainPackageAs(newPkg)) { + op.keep(currItem); + op.keep(cat); + continue nextPkg; + } else if (currItem.hasUpdatePkg() && + currItem.isSameUpdatePackageAs(newPkg)) { + op.keep(currItem.getUpdatePkg()); + op.keep(cat); + continue nextPkg; + } - if (item.hasUpdatePkg()) { - Package newPkg = setContainsLocalPackage(newPackages, item.getUpdatePkg()); - if (newPkg != null) { - removePackageFromSet(unusedPackages, newPkg); - } else { - // This update is no longer part of the source - item.removeUpdate(); - hasChanged = true; + switch (currItem.getState()) { + case NEW: + if (newPkg.getRevision() < mainPkg.getRevision()) { + if (!op.isKeep(currItem)) { + // The new item has a lower revision than the current one, + // but the current one hasn't been marked as being kept so + // it's ok to downgrade it. + currItemIt.remove(); + addNewItem(op, newPkg, PkgState.NEW); + hasChanged = true; + } + } else if (newPkg.getRevision() > mainPkg.getRevision()) { + // We have a more recent new version, remove the current one + // and replace by a new one + currItemIt.remove(); + addNewItem(op, newPkg, PkgState.NEW); + hasChanged = true; + } + break; + case INSTALLED: + // if newPkg.revision <= mainPkg.revision: it's already installed, ignore. + if (newPkg.getRevision() > mainPkg.getRevision()) { + // This is a new update for the main package. + if (currItem.mergeUpdate(newPkg)) { + op.keep(currItem.getUpdatePkg()); + op.keep(cat); + hasChanged = true; + } + } + break; + } + continue nextPkg; } } } - } - - // Add any new unknown packages - for (Package newPackage : unusedPackages) { - Object catKey = op.getCategoryKey(newPackage); - PkgCategory cat = findCurrentCategory(op.getCategories(), catKey); - - if (cat == null) { - // This is a new category. Create it and add it to the list. - cat = op.createCategory(catKey); - op.getCategories().add(cat); - op.sortCategoryList(); - } - - // Add the new package or merge it as an update - hasChanged |= op.mergeNewPackage(newPackage, cat); + // If not found, create a new package item + addNewItem(op, newPkg, PkgState.NEW); + hasChanged = true; } if (hasChanged) { @@ -650,75 +553,25 @@ class PackagesDiffLogic { return hasChanged; } - private boolean isSourceCompatible(PkgItem currentItem, Package newPackage) { - assert currentItem != null; - assert newPackage != null; - - // Don't compare source of packages which are not the same (their revision # can differ) - Package currentPkg = currentItem.getMainPackage(); - if (!currentPkg.sameItemAs(newPackage)) { - return false; - } - - SdkSource currentSource = currentItem.getSource(); - SdkSource newItemSource = newPackage.getParentSource(); - - // Only process items matching the current source. - if (currentSource == newItemSource) { - // Object identity, so definitely the same source. Accept it. - return true; - - } else if (currentSource != null && currentSource.equals(newItemSource)) { - // Same source. Accept it. - return true; - - } else if (currentSource != null && newItemSource != null && - !currentSource.getClass().equals(newItemSource.getClass())) { - // Both sources don't have the same type (e.g. sdk repository versus add-on repository) - return false; - - } else if (currentSource == null && currentItem.getState() == PkgState.INSTALLED) { - // Accept it. - // If a locally installed item has no source, it probably has been - // manually installed. In this case just match any remote source. - return true; - - } else if (currentSource != null && currentSource.getUrl().startsWith("file://")) { - // Heuristic: Probably a manual local install. Accept it. - return true; - } - - // Reject the source mismatch. The idea is that if two remote repositories - // have similar packages, we don't want to merge them together and have - // one hide the other. This is a design error from the repository owners - // and we want the case to be blatant so that we can get it fixed. - - if (currentSource != null && newItemSource != null) { - try { - String str1 = rewriteUrl(currentSource.getUrl()); - String str2 = rewriteUrl(newItemSource.getUrl()); - - URL url1 = new URL(str1); - URL url2 = new URL(str2); + private PkgItem addNewItem(UpdateOp op, Package pkg, PkgState state) { + List<PkgCategory> cats = op.getCategories(); + Object catKey = op.getCategoryKey(pkg); + PkgCategory cat = findCurrentCategory(cats, catKey); - // Make an exception if both URLs have the same host name & domain name. - if (url1.sameFile(url2) || url1.getHost().equals(url2.getHost())) { - return true; - } - } catch (Exception ignore) { - // Ignore MalformedURLException or other exceptions + if (cat == null) { + // This is a new category. Create it and add it to the list. + cat = op.createCategory(catKey); + synchronized (cats) { + cats.add(cat); } + op.sortCategoryList(); } - return false; - } - - private String rewriteUrl(String url) { - if (url != null && url.startsWith(SdkRepoConstants.URL_GOOGLE_SDK_SITE)) { - url = url.replaceAll("repository-[0-9]+\\.xml^", //$NON-NLS-1$ - "repository.xml"); //$NON-NLS-1$ - } - return url; + PkgItem item = new PkgItem(pkg, state); + op.keep(item); + cat.getItems().add(item); + op.keep(cat); + return item; } private PkgCategory findCurrentCategory( @@ -756,13 +609,14 @@ class PackagesDiffLogic { boolean needTools = true; boolean needExtras = true; - for (PkgCategory cat : mCategories) { + List<PkgCategory> cats = getCategories(); + for (PkgCategory cat : cats) { if (cat.getKey().equals(PkgCategoryApi.KEY_TOOLS)) { // Mark them as no unused to prevent their removal in updateEnd(). - cat.setUnused(false); + keep(cat); needTools = false; } else if (cat.getKey().equals(PkgCategoryApi.KEY_EXTRA)) { - cat.setUnused(false); + keep(cat); needExtras = false; } } @@ -773,8 +627,8 @@ class PackagesDiffLogic { PkgCategoryApi.KEY_TOOLS, null, mUpdaterData.getImageFactory().getImageByName(PackagesPage.ICON_CAT_OTHER)); - synchronized (mCategories) { - mCategories.add(acat); + synchronized (cats) { + cats.add(acat); } } @@ -783,8 +637,8 @@ class PackagesDiffLogic { PkgCategoryApi.KEY_EXTRA, null, mUpdaterData.getImageFactory().getImageByName(PackagesPage.ICON_CAT_OTHER)); - synchronized (mCategories) { - mCategories.add(acat); + synchronized (cats) { + cats.add(acat); } } } @@ -823,35 +677,6 @@ class PackagesDiffLogic { } @Override - public boolean mergeNewPackage(Package newPackage, PkgCategory cat) { - // First check if the new package could be an update - // to an existing package - for (PkgItem item : cat.getItems()) { - if (!isSourceCompatible(item, newPackage)) { - continue; - } - - if (item.isSameMainPackageAs(newPackage)) { - // Seems like this isn't really a new item after all. - cat.setUnused(false); - // Return false since we're not changing anything. - return false; - } else if (item.mergeUpdate(newPackage)) { - // The new package is an update for the existing package - // and has been merged in the PkgItem as such. - cat.setUnused(false); - // Return true to indicate we changed something. - return true; - } - } - - // This is truly a new item. - cat.getItems().add(new PkgItem(newPackage, PkgState.NEW)); - cat.setUnused(false); - return true; // something has changed - } - - @Override public void sortCategoryList() { // Sort the categories list. // We always want categories in order tools..platforms..extras. @@ -859,8 +684,8 @@ class PackagesDiffLogic { // This order is achieved by having the category keys ordered as // needed for the sort to just do what we expect. - synchronized (mCategories) { - Collections.sort(mCategories, new Comparator<PkgCategory>() { + synchronized (getCategories()) { + Collections.sort(getCategories(), new Comparator<PkgCategory>() { public int compare(PkgCategory cat1, PkgCategory cat2) { assert cat1 instanceof PkgCategoryApi; assert cat2 instanceof PkgCategoryApi; @@ -875,7 +700,7 @@ class PackagesDiffLogic { @Override public void postCategoryItemsChanged() { // Sort the items - for (PkgCategory cat : mCategories) { + for (PkgCategory cat : getCategories()) { Collections.sort(cat.getItems()); // When sorting by API, we can't always get the platform name @@ -922,7 +747,8 @@ class PackagesDiffLogic { @Override public void addDefaultCategories() { - for (PkgCategory cat : mCategories) { + List<PkgCategory> cats = getCategories(); + for (PkgCategory cat : cats) { if (cat.getKey().equals(PkgCategorySource.UNKNOWN_SOURCE)) { // Already present. return; @@ -933,10 +759,10 @@ class PackagesDiffLogic { PkgCategorySource cat = new PkgCategorySource( PkgCategorySource.UNKNOWN_SOURCE, mUpdaterData); - // Mark it as unused so that it can be cleared in updateEnd() if not used. - cat.setUnused(true); - synchronized (mCategories) { - mCategories.add(cat); + // Mark it so that it can be cleared in updateEnd() if not used. + dontKeep(cat); + synchronized (cats) { + cats.add(cat); } } @@ -949,37 +775,12 @@ class PackagesDiffLogic { } @Override - public boolean mergeNewPackage(Package newPackage, PkgCategory cat) { - // First check if the new package could be an update - // to an existing package - for (PkgItem item : cat.getItems()) { - if (item.isSameMainPackageAs(newPackage)) { - // Seems like this isn't really a new item after all. - cat.setUnused(false); - // Return false since we're not changing anything. - return false; - } else if (item.mergeUpdate(newPackage)) { - // The new package is an update for the existing package - // and has been merged in the PkgItem as such. - cat.setUnused(false); - // Return true to indicate we changed something. - return true; - } - } - - // This is truly a new item. - cat.getItems().add(new PkgItem(newPackage, PkgState.NEW)); - cat.setUnused(false); - return true; // something has changed - } - - @Override public void sortCategoryList() { // Sort the sources in ascending source name order, // with the local packages always first. - synchronized (mCategories) { - Collections.sort(mCategories, new Comparator<PkgCategory>() { + synchronized (getCategories()) { + Collections.sort(getCategories(), new Comparator<PkgCategory>() { public int compare(PkgCategory cat1, PkgCategory cat2) { assert cat1 instanceof PkgCategorySource; assert cat2 instanceof PkgCategorySource; @@ -1005,7 +806,7 @@ class PackagesDiffLogic { @Override public void postCategoryItemsChanged() { // Sort the items - for (PkgCategory cat : mCategories) { + for (PkgCategory cat : getCategories()) { Collections.sort(cat.getItems()); } } diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgCategory.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgCategory.java index 5bfd689..b682f08 100755 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgCategory.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgCategory.java @@ -20,12 +20,10 @@ import java.util.ArrayList; import java.util.List; abstract class PkgCategory { - private final Object mKey; - private final Object mIconRef; - private final List<PkgItem> mItems = new ArrayList<PkgItem>(); - private String mLabel; - /** Transient flag used during incremental updates. */ - private boolean mUnused; + private final Object mKey; + private final Object mIconRef; + private final List<PkgItem> mItems = new ArrayList<PkgItem>(); + private String mLabel; public PkgCategory(Object key, String label, Object iconRef) { mKey = key; @@ -53,14 +51,6 @@ abstract class PkgCategory { return mItems; } - public void setUnused(boolean unused) { - mUnused = unused; - } - - public boolean isUnused() { - return mUnused; - } - @Override public String toString() { return String.format("%s <key=%s, label=%s, #items=%d>", diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgItem.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgItem.java index d5eb0a3..0f9dbc3 100755 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgItem.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgItem.java @@ -40,6 +40,9 @@ public class PkgItem implements Comparable<PkgItem> { * a given remote package and the local repository. */ public enum PkgState { + // Implementation detail: order matters. Installed items must be dealt with before + // new items and the order of PkgState.values() matters. + /** * Package is locally installed and may or may not have an update. */ @@ -156,6 +159,18 @@ public class PkgItem implements Comparable<PkgItem> { } /** + * Checks whether the update packages are of the same type and are + * not an update of each other. + */ + public boolean isSameUpdatePackageAs(Package pkg) { + if (mUpdatePkg != null && mUpdatePkg.canBeUpdatedBy(pkg) == UpdateInfo.NOT_UPDATE) { + // package revision numbers must match + return mUpdatePkg.getRevision() == pkg.getRevision(); + } + return false; + } + + /** * Checks whether too {@link PkgItem} are the same. * This checks both items have the same state, both main package are similar * and that they have the same updating packages. |