aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java18
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java9
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SystemImagePackage.java17
-rwxr-xr-xsdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/LocalSdkParserTest.java4
-rwxr-xr-xsdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/SdkRepoSourceTest.java4
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogic.java583
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgCategory.java18
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/sdkman2/PkgItem.java15
-rwxr-xr-xsdkmanager/libs/sdkuilib/tests/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogicTest.java83
9 files changed, 307 insertions, 444 deletions
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
index 98c39be..385bd73 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
@@ -495,4 +495,22 @@ public class AddonPackage extends Package
}
return true;
}
+
+ /**
+ * For addon packages, we want to add vendor|name to the sorting key
+ * <em>before<em/> the revision number.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ protected String comparisonKey() {
+ String s = super.comparisonKey();
+ int pos = s.indexOf("|r:"); //$NON-NLS-1$
+ assert pos > 0;
+ s = s.substring(0, pos) +
+ "|ve:" + getVendor() + //$NON-NLS-1$
+ "|na:" + getName() + //$NON-NLS-1$
+ s.substring(pos);
+ return s;
+ }
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
index b99da5c..01f713a 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
@@ -672,14 +672,13 @@ public abstract class Package implements IDescription, Comparable<Package> {
// extras and everything else
sb.append(9);
}
- sb.append("|v:"); //$NON-NLS-1$
// We insert the package version here because it is more important
// than the revision number. We want package version to be sorted
// top-down, so we'll use 10k-api as the sorting key. The day we
// get reach 10k APIs, we'll need to revisit this.
-
+ sb.append("|v:"); //$NON-NLS-1$
if (this instanceof IPackageVersion) {
AndroidVersion v = ((IPackageVersion) this).getVersion();
@@ -688,14 +687,12 @@ public abstract class Package implements IDescription, Comparable<Package> {
v.isPreview() ? 1 : 0
));
}
- sb.append("|r:"); //$NON-NLS-1$
-
// Append revision number
-
+ sb.append("|r:"); //$NON-NLS-1$
sb.append(String.format("%1$04d", getRevision())); //$NON-NLS-1$
- sb.append('|');
+ sb.append('|');
return sb.toString();
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SystemImagePackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SystemImagePackage.java
index 3e8363c..877a1d1 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SystemImagePackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SystemImagePackage.java
@@ -351,4 +351,21 @@ public class SystemImagePackage extends Package
}
return true;
}
+
+ /**
+ * For sys img packages, we want to add abi to the sorting key
+ * <em>before<em/> the revision number.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ protected String comparisonKey() {
+ String s = super.comparisonKey();
+ int pos = s.indexOf("|r:"); //$NON-NLS-1$
+ assert pos > 0;
+ s = s.substring(0, pos) +
+ "|abi:" + getAbiDisplayName() + //$NON-NLS-1$
+ s.substring(pos);
+ return s;
+ }
}
diff --git a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/LocalSdkParserTest.java b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/LocalSdkParserTest.java
index aa503cd..017d17c 100755
--- a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/LocalSdkParserTest.java
+++ b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/LocalSdkParserTest.java
@@ -70,8 +70,8 @@ public class LocalSdkParserTest extends SdkManagerTestCase {
assertEquals(
"[SDK Platform Android 0.0, API 0, revision 1, " +
- "ARM EABI System Image, Android API 0, revision 0, " +
"ARM EABI v7a System Image, Android API 0, revision 0, " +
+ "ARM EABI System Image, Android API 0, revision 0, " +
"Sources for Android SDK, API 0, revision 0]",
Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
@@ -84,8 +84,8 @@ public class LocalSdkParserTest extends SdkManagerTestCase {
assertEquals(
"[SDK Platform Android 0.0, API 0, revision 1, " +
- "ARM EABI System Image, Android API 0, revision 0, " +
"ARM EABI v7a System Image, Android API 0, revision 0, " +
+ "ARM EABI System Image, Android API 0, revision 0, " +
"Sources for Android SDK, API 0, revision 0, " +
"Broken Intel x86 Atom System Image, API 0]",
Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
diff --git a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/SdkRepoSourceTest.java b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/SdkRepoSourceTest.java
index 10330bc..564dfed 100755
--- a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/SdkRepoSourceTest.java
+++ b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/SdkRepoSourceTest.java
@@ -667,8 +667,8 @@ public class SdkRepoSourceTest extends TestCase {
}
assertEquals(
"[42 armeabi, " +
- "2 x86, " +
- "2 armeabi-v7a]",
+ "2 armeabi-v7a, " +
+ "2 x86]",
Arrays.toString(sysImgVersionAbi.toArray()));
// Check the source packages
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.
diff --git a/sdkmanager/libs/sdkuilib/tests/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogicTest.java b/sdkmanager/libs/sdkuilib/tests/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogicTest.java
index c378fbb..c2b320d 100755
--- a/sdkmanager/libs/sdkuilib/tests/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogicTest.java
+++ b/sdkmanager/libs/sdkuilib/tests/com/android/sdkuilib/internal/repository/sdkman2/PackagesDiffLogicTest.java
@@ -379,6 +379,8 @@ public class PackagesDiffLogicTest extends TestCase {
m.updateStart();
MockPlatformPackage p1;
MockPlatformPackage p2;
+ @SuppressWarnings("unused") // keep p3 for clarity
+ MockPlatformPackage p3;
assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -386,8 +388,9 @@ public class PackagesDiffLogicTest extends TestCase {
new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
// second update
p1 = new MockPlatformPackage(src1, 1, 2, 3), // API 1
- new MockPlatformPackage(src1, 3, 6, 3),
+ p3 = new MockPlatformPackage(src1, 3, 6, 3),
new MockAddonPackage(src2, "addon A", p1, 5),
+ new MockAddonPackage(src2, "addon D", p1, 10),
}));
assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -400,10 +403,15 @@ public class PackagesDiffLogicTest extends TestCase {
assertTrue(m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
new MockAddonPackage(src2, "addon C", p2, 9),
new MockAddonPackage(src2, "addon A", p1, 6),
+ // the rev 7+8 will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 7),
- // the rev 8 update will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 8),
new MockAddonPackage(src2, "addon B", p2, 9),
+ // 11+12 should be ignored updates, 13 will update 10
+ new MockAddonPackage(src2, "addon D", p1, 10),
+ new MockAddonPackage(src2, "addon D", p1, 12), // note: 12 listed before 11
+ new MockAddonPackage(src2, "addon D", p1, 11),
+ new MockAddonPackage(src2, "addon D", p1, 13),
}));
assertFalse(m.updateEnd(true /*sortByApi*/));
@@ -415,11 +423,12 @@ public class PackagesDiffLogicTest extends TestCase {
"-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
"PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=3>\n" +
"-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
- "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
+ "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 9>\n" +
"-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
- "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
+ "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=3>\n" +
"-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
"-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
+ "-- <INSTALLED, pkg:addon D by vendor 1, Android API 1, revision 10, updated by:addon D by vendor 1, Android API 1, revision 13>\n" +
"PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
"-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
"-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
@@ -435,8 +444,9 @@ public class PackagesDiffLogicTest extends TestCase {
new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
// second update
p1 = new MockPlatformPackage(src1, 1, 2, 3),
- new MockPlatformPackage(src1, 3, 6, 3),
+ p3 = new MockPlatformPackage(src1, 3, 6, 3),
new MockAddonPackage(src2, "addon A", p1, 5),
+ new MockAddonPackage(src2, "addon D", p1, 10),
}));
assertFalse(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -449,12 +459,15 @@ public class PackagesDiffLogicTest extends TestCase {
assertTrue(m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
new MockAddonPackage(src2, "addon C", p2, 9),
new MockAddonPackage(src2, "addon A", p1, 6),
+ // the rev 7+8 will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 7),
- // the rev 8 update will be ignored since there's a rev 9 coming after
- // however as a side effect it makes the update method return true as it
- // incorporated the update.
new MockAddonPackage(src2, "addon B", p2, 8),
new MockAddonPackage(src2, "addon B", p2, 9),
+ // 11+12 should be ignored updates, 13 will update 10
+ new MockAddonPackage(src2, "addon D", p1, 10),
+ new MockAddonPackage(src2, "addon D", p1, 12), // note: 12 listed before 11
+ new MockAddonPackage(src2, "addon D", p1, 11),
+ new MockAddonPackage(src2, "addon D", p1, 13),
}));
assertFalse(m.updateEnd(true /*sortByApi*/));
@@ -466,11 +479,12 @@ public class PackagesDiffLogicTest extends TestCase {
"-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
"PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=3>\n" +
"-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
- "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
+ "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 9>\n" +
"-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
- "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
+ "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=3>\n" +
"-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
"-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
+ "-- <INSTALLED, pkg:addon D by vendor 1, Android API 1, revision 10, updated by:addon D by vendor 1, Android API 1, revision 13>\n" +
"PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
"-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
"-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
@@ -708,6 +722,8 @@ public class PackagesDiffLogicTest extends TestCase {
m.updateStart();
MockPlatformPackage p1;
MockPlatformPackage p2;
+ @SuppressWarnings("unused") // keep p3 for clarity
+ MockPlatformPackage p3;
assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -715,8 +731,10 @@ public class PackagesDiffLogicTest extends TestCase {
new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
// second update
p1 = new MockPlatformPackage(src1, 1, 2, 3), // API 1
+ p3 = new MockPlatformPackage(src1, 3, 6, 3),
new MockPlatformPackage(src1, 3, 6, 3), // API 3
new MockAddonPackage(src2, "addon A", p1, 5),
+ new MockAddonPackage(src2, "addon D", p1, 10),
}));
assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -729,10 +747,15 @@ public class PackagesDiffLogicTest extends TestCase {
assertTrue(m.updateSourcePackages(false /*sortByApi*/, src2, new Package[] {
new MockAddonPackage(src2, "addon C", p2, 9),
new MockAddonPackage(src2, "addon A", p1, 6),
+ // the rev 7+8 will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 7),
- // the rev 8 update will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 8),
new MockAddonPackage(src2, "addon B", p2, 9),
+ // 11+12 should be ignored updates, 13 will update 10
+ new MockAddonPackage(src2, "addon D", p1, 10),
+ new MockAddonPackage(src2, "addon D", p1, 12), // note: 12 listed before 11
+ new MockAddonPackage(src2, "addon D", p1, 11),
+ new MockAddonPackage(src2, "addon D", p1, 13),
}));
assertTrue(m.updateEnd(false /*sortByApi*/));
@@ -745,10 +768,11 @@ public class PackagesDiffLogicTest extends TestCase {
"-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
"-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
"-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n" +
- "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
- "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
+ "PkgCategorySource <source=repo2 (2.example.com), #items=4>\n" +
+ "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 9>\n" +
"-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
- "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n",
+ "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
+ "-- <INSTALLED, pkg:addon D by vendor 1, Android API 1, revision 10, updated by:addon D by vendor 1, Android API 1, revision 13>\n",
getTree(m, false /*displaySortByApi*/));
// Reloading the same thing should have no impact except for the update methods
@@ -760,9 +784,11 @@ public class PackagesDiffLogicTest extends TestCase {
new MockPlatformToolPackage(src1, 3),
new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
// second update
- p1 = new MockPlatformPackage(src1, 1, 2, 3),
- new MockPlatformPackage(src1, 3, 6, 3),
+ p1 = new MockPlatformPackage(src1, 1, 2, 3), // API 1
+ p3 = new MockPlatformPackage(src1, 3, 6, 3),
+ new MockPlatformPackage(src1, 3, 6, 3), // API 3
new MockAddonPackage(src2, "addon A", p1, 5),
+ new MockAddonPackage(src2, "addon D", p1, 10),
}));
assertFalse(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
new MockToolPackage(src1, 10, 3),
@@ -775,12 +801,15 @@ public class PackagesDiffLogicTest extends TestCase {
assertTrue(m.updateSourcePackages(false /*sortByApi*/, src2, new Package[] {
new MockAddonPackage(src2, "addon C", p2, 9),
new MockAddonPackage(src2, "addon A", p1, 6),
+ // the rev 7+8 will be ignored since there's a rev 9 coming after
new MockAddonPackage(src2, "addon B", p2, 7),
- // the rev 8 update will be ignored since there's a rev 9 coming after
- // however as a side effect it makes the update method return true as it
- // incorporated the update.
new MockAddonPackage(src2, "addon B", p2, 8),
new MockAddonPackage(src2, "addon B", p2, 9),
+ // 11+12 should be ignored updates, 13 will update 10
+ new MockAddonPackage(src2, "addon D", p1, 10),
+ new MockAddonPackage(src2, "addon D", p1, 12), // note: 12 listed before 11
+ new MockAddonPackage(src2, "addon D", p1, 11),
+ new MockAddonPackage(src2, "addon D", p1, 13),
}));
assertTrue(m.updateEnd(false /*sortByApi*/));
@@ -793,10 +822,11 @@ public class PackagesDiffLogicTest extends TestCase {
"-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
"-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
"-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n" +
- "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
- "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
+ "PkgCategorySource <source=repo2 (2.example.com), #items=4>\n" +
+ "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 9>\n" +
"-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
- "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n",
+ "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
+ "-- <INSTALLED, pkg:addon D by vendor 1, Android API 1, revision 10, updated by:addon D by vendor 1, Android API 1, revision 13>\n",
getTree(m, false /*displaySortByApi*/));
}
@@ -1387,13 +1417,8 @@ public class PackagesDiffLogicTest extends TestCase {
getTree(m, true /*displaySortByApi*/));
assertEquals(
"PkgCategorySource <source=Local Packages (no.source), #items=1>\n" +
- // FIXME: tools rev 3 is installed in one source, and there's a rev 4 update
- // it a different source. We should still mark the rev 3 here as having an update.
- // We typically don't want to hide the fact the update comes from a different
- // source but here it's OK since the local package has no source defined.
- "-- <INSTALLED, pkg:Android SDK Tools, revision 3>\n" + // ERROR: missing update 4
- "PkgCategorySource <source=repo1 (1.example.com), #items=3>\n" +
- "-- <NEW, pkg:Android SDK Tools, revision 4>\n" +
+ "-- <INSTALLED, pkg:Android SDK Tools, revision 3, updated by:Android SDK Tools, revision 4>\n" +
+ "PkgCategorySource <source=repo1 (1.example.com), #items=2>\n" +
"-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3, updated by:Android SDK Platform-tools, revision 4>\n" +
"-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
"PkgCategorySource <source=repo2 (2.example.com), #items=2>\n" +