Merge change Ib096f1f0 into eclair

* changes:
  SDK Manager: suggest install of new platforms, addons or extra packages.
This commit is contained in:
Android (Google) Code Review
2009-10-13 00:38:11 -04:00
9 changed files with 328 additions and 55 deletions

View File

@@ -36,6 +36,16 @@ import java.util.Map.Entry;
*/ */
class CommandLineProcessor { class CommandLineProcessor {
/*
* Steps needed to add a new action:
* - Each action is defined as a "verb object" followed by parameters.
* - Either reuse a VERB_ constant or define a new one.
* - Either reuse an OBJECT_ constant or define a new one.
* - Add a new entry to mAction with a one-line help summary.
* - In the constructor, add a define() call for each parameter (either mandatory
* or optional) for the given action.
*/
/** Internal verb name for internally hidden flags. */ /** Internal verb name for internally hidden flags. */
public final static String GLOBAL_FLAG_VERB = "@@internal@@"; public final static String GLOBAL_FLAG_VERB = "@@internal@@";
@@ -57,10 +67,14 @@ class CommandLineProcessor {
/** /**
* Action definitions. * Action definitions.
* <p/> * <p/>
* This list serves two purposes: first it is used to know which verb/object
* actions are acceptable on the command-line; second it provides a summary
* for each action that is printed in the help.
* <p/>
* Each entry is a string array with: * Each entry is a string array with:
* <ul> * <ul>
* <li> the verb. * <li> the verb.
* <li> a direct object (use #NO_VERB_OBJECT if there's no object). * <li> a direct object (use {@link #NO_VERB_OBJECT} if there's no object).
* <li> a description. * <li> a description.
* <li> an alternate form for the object (e.g. plural). * <li> an alternate form for the object (e.g. plural).
* </ul> * </ul>
@@ -81,6 +95,15 @@ class CommandLineProcessor {
/** Logger */ /** Logger */
private final ISdkLog mLog; private final ISdkLog mLog;
/**
* Constructs a new command-line processor.
*
* @param logger An SDK logger object. Must not be null.
* @param actions The list of actions recognized on the command-line.
* See the javadoc of {@link #mActions} for more details.
*
* @see #mActions
*/
public CommandLineProcessor(ISdkLog logger, String[][] actions) { public CommandLineProcessor(ISdkLog logger, String[][] actions) {
mLog = logger; mLog = logger;
mActions = actions; mActions = actions;

View File

@@ -34,6 +34,7 @@ import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
import com.android.sdklib.xml.AndroidXPathFactory; import com.android.sdklib.xml.AndroidXPathFactory;
import com.android.sdkmanager.internal.repository.AboutPage; import com.android.sdkmanager.internal.repository.AboutPage;
import com.android.sdkmanager.internal.repository.SettingsPage; import com.android.sdkmanager.internal.repository.SettingsPage;
import com.android.sdkuilib.internal.repository.LocalPackagesPage;
import com.android.sdkuilib.repository.UpdaterWindow; import com.android.sdkuilib.repository.UpdaterWindow;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
@@ -243,7 +244,11 @@ public class Main {
updateTestProject(); updateTestProject();
} else if (verb == null && directObject == null) { } else if (verb == null && directObject == null) {
showMainWindow(); showMainWindow(false /*autoUpdate*/);
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_SDK.equals(directObject)) {
showMainWindow(true /*autoUpdate*/);
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) && } else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_ADB.equals(directObject)) { SdkCommandLine.OBJECT_ADB.equals(directObject)) {
@@ -257,7 +262,7 @@ public class Main {
/** /**
* Display the main SdkManager app window * Display the main SdkManager app window
*/ */
private void showMainWindow() { private void showMainWindow(boolean autoUpdate) {
try { try {
// display a message talking about the command line version // display a message talking about the command line version
System.out.printf("No command line parameters provided, launching UI.\n" + System.out.printf("No command line parameters provided, launching UI.\n" +
@@ -269,6 +274,10 @@ public class Main {
false /*userCanChangeSdkRoot*/); false /*userCanChangeSdkRoot*/);
window.registerPage("Settings", SettingsPage.class); window.registerPage("Settings", SettingsPage.class);
window.registerPage("About", AboutPage.class); window.registerPage("About", AboutPage.class);
if (autoUpdate) {
window.setInitialPage(LocalPackagesPage.class);
window.setRequestAutoUpdate(true);
}
window.open(); window.open();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -353,12 +362,14 @@ public class Main {
} catch (IOException e) { } catch (IOException e) {
errorAndExit("Unable to resolve Main project's directory: %1$s", errorAndExit("Unable to resolve Main project's directory: %1$s",
pathToMainProject); pathToMainProject);
return; // help Eclipse static analyzer understand we'll never execute the rest.
} }
} }
if (parentProject.isDirectory() == false) { if (parentProject.isDirectory() == false) {
errorAndExit("Main project's directory does not exist: %1$s", errorAndExit("Main project's directory does not exist: %1$s",
pathToMainProject); pathToMainProject);
return;
} }
// now look for a manifest in there // now look for a manifest in there
@@ -366,6 +377,7 @@ public class Main {
if (manifest.isFile() == false) { if (manifest.isFile() == false) {
errorAndExit("No AndroidManifest.xml file found in the main project directory: %1$s", errorAndExit("No AndroidManifest.xml file found in the main project directory: %1$s",
parentProject.getAbsolutePath()); parentProject.getAbsolutePath());
return;
} }
// now query the manifest for the package file. // now query the manifest for the package file.
@@ -405,6 +417,7 @@ public class Main {
String targetHash = p.getProperty(ProjectProperties.PROPERTY_TARGET); String targetHash = p.getProperty(ProjectProperties.PROPERTY_TARGET);
if (targetHash == null) { if (targetHash == null) {
errorAndExit("Couldn't find the main project target"); errorAndExit("Couldn't find the main project target");
return;
} }
// and resolve it. // and resolve it.
@@ -413,6 +426,7 @@ public class Main {
errorAndExit( errorAndExit(
"Unable to resolve main project target '%1$s'. You may want to install the platform in your SDK.", "Unable to resolve main project target '%1$s'. You may want to install the platform in your SDK.",
targetHash); targetHash);
return;
} }
mSdkLog.printf("Found main project target: %1$s\n", target.getFullName()); mSdkLog.printf("Found main project target: %1$s\n", target.getFullName());

View File

@@ -25,12 +25,23 @@ import com.android.sdklib.SdkManager;
*/ */
class SdkCommandLine extends CommandLineProcessor { class SdkCommandLine extends CommandLineProcessor {
/*
* Steps needed to add a new action:
* - Each action is defined as a "verb object" followed by parameters.
* - Either reuse a VERB_ constant or define a new one.
* - Either reuse an OBJECT_ constant or define a new one.
* - Add a new entry to mAction with a one-line help summary.
* - In the constructor, add a define() call for each parameter (either mandatory
* or optional) for the given action.
*/
public final static String VERB_LIST = "list"; public final static String VERB_LIST = "list";
public final static String VERB_CREATE = "create"; public final static String VERB_CREATE = "create";
public final static String VERB_MOVE = "move"; public final static String VERB_MOVE = "move";
public final static String VERB_DELETE = "delete"; public final static String VERB_DELETE = "delete";
public final static String VERB_UPDATE = "update"; public final static String VERB_UPDATE = "update";
public static final String OBJECT_SDK = "sdk";
public static final String OBJECT_AVD = "avd"; public static final String OBJECT_AVD = "avd";
public static final String OBJECT_AVDS = "avds"; public static final String OBJECT_AVDS = "avds";
public static final String OBJECT_TARGET = "target"; public static final String OBJECT_TARGET = "target";
@@ -59,6 +70,10 @@ class SdkCommandLine extends CommandLineProcessor {
/** /**
* Action definitions for SdkManager command line. * Action definitions for SdkManager command line.
* <p/> * <p/>
* This list serves two purposes: first it is used to know which verb/object
* actions are acceptable on the command-line; second it provides a summary
* for each action that is printed in the help.
* <p/>
* Each entry is a string array with: * Each entry is a string array with:
* <ul> * <ul>
* <li> the verb. * <li> the verb.
@@ -98,11 +113,16 @@ class SdkCommandLine extends CommandLineProcessor {
{ VERB_UPDATE, OBJECT_ADB, { VERB_UPDATE, OBJECT_ADB,
"Updates adb to support the USB devices declared in the SDK add-ons." }, "Updates adb to support the USB devices declared in the SDK add-ons." },
{ VERB_UPDATE, OBJECT_SDK,
"Updates the SDK by suggesting new platforms to install if available." }
}; };
public SdkCommandLine(ISdkLog logger) { public SdkCommandLine(ISdkLog logger) {
super(logger, ACTIONS); super(logger, ACTIONS);
// The following defines the parameters of the actions defined in mAction.
// --- create avd --- // --- create avd ---
define(Mode.STRING, false, define(Mode.STRING, false,
@@ -175,6 +195,7 @@ class SdkCommandLine extends CommandLineProcessor {
"Project name", null); "Project name", null);
// --- create test-project --- // --- create test-project ---
define(Mode.STRING, true, define(Mode.STRING, true,
VERB_CREATE, OBJECT_TEST_PROJECT, VERB_CREATE, OBJECT_TEST_PROJECT,
"p", KEY_PATH, "p", KEY_PATH,

View File

@@ -124,7 +124,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
mUpdateButton.addSelectionListener(new SelectionAdapter() { mUpdateButton.addSelectionListener(new SelectionAdapter() {
@Override @Override
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent e) {
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer) onUpdateSelected(); //$hide$ (hide from SWT designer)
} }
}); });
@@ -255,7 +255,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
mDescriptionLabel.setText(""); //$NON-NLS1-$ mDescriptionLabel.setText(""); //$NON-NLS1-$
} }
private void onUpdateInstalledPackage() { private void onUpdateSelected() {
mUpdaterData.updateOrInstallAll(null /*selectedArchives*/); mUpdaterData.updateOrInstallAll(null /*selectedArchives*/);
} }

View File

@@ -146,12 +146,14 @@ class UpdaterData {
return mSettingsController; return mSettingsController;
} }
/** Adds a listener ({@link ISdkListener}) that is notified when the SDK is reloaded. */
public void addListeners(ISdkListener listener) { public void addListeners(ISdkListener listener) {
if (mListeners.contains(listener) == false) { if (mListeners.contains(listener) == false) {
mListeners.add(listener); mListeners.add(listener);
} }
} }
/** Removes a listener ({@link ISdkListener}) that is notified when the SDK is reloaded. */
public void removeListener(ISdkListener listener) { public void removeListener(ISdkListener listener) {
mListeners.remove(listener); mListeners.remove(listener);
} }
@@ -444,9 +446,15 @@ class UpdaterData {
/** /**
* Tries to update all the *existing* local packages. * Tries to update all the *existing* local packages.
* This first refreshes all sources, then compares the available remote packages with * <p/>
* the current local ones and suggest updates to be done to the user. Finally all * There are two modes of operation:
* selected updates are installed. * <ul>
* <li>If selectedArchives is null, refreshes all sources, compares the available remote
* packages with the current local ones and suggest updates to be done to the user (including
* new platforms that the users doesn't have yet).
* <li>If selectedArchives is not null, this represents a list of archives/packages that
* the user wants to install or update, so just process these.
* </ul>
* *
* @param selectedArchives The list of remote archive to consider for the update. * @param selectedArchives The list of remote archive to consider for the update.
* This can be null, in which case a list of remote archive is fetched from all * This can be null, in which case a list of remote archive is fetched from all
@@ -463,6 +471,13 @@ class UpdaterData {
getSources(), getSources(),
getLocalSdkParser().getPackages()); getLocalSdkParser().getPackages());
if (selectedArchives == null) {
ul.addNewPlatforms(archives, getSources(), getLocalSdkParser().getPackages());
}
// TODO if selectedArchives is null and archives.len==0, find if there's
// any new platform we can suggest to install instead.
UpdateChooserDialog dialog = new UpdateChooserDialog(getWindowShell(), this, archives); UpdateChooserDialog dialog = new UpdateChooserDialog(getWindowShell(), this, archives);
dialog.open(); dialog.open();

View File

@@ -19,6 +19,7 @@ package com.android.sdkuilib.internal.repository;
import com.android.sdklib.AndroidVersion; import com.android.sdklib.AndroidVersion;
import com.android.sdklib.internal.repository.AddonPackage; import com.android.sdklib.internal.repository.AddonPackage;
import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.Archive;
import com.android.sdklib.internal.repository.ExtraPackage;
import com.android.sdklib.internal.repository.MinToolsPackage; import com.android.sdklib.internal.repository.MinToolsPackage;
import com.android.sdklib.internal.repository.Package; import com.android.sdklib.internal.repository.Package;
import com.android.sdklib.internal.repository.PlatformPackage; import com.android.sdklib.internal.repository.PlatformPackage;
@@ -29,6 +30,7 @@ import com.android.sdklib.internal.repository.Package.UpdateInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
/** /**
* The logic to compute which packages to install, based on the choices * The logic to compute which packages to install, based on the choices
@@ -39,8 +41,6 @@ import java.util.Collection;
*/ */
class UpdaterLogic { class UpdaterLogic {
private RepoSources mSources;
/** /**
* Compute which packages to install by taking the user selection * Compute which packages to install by taking the user selection
* and adding dependent packages as needed. * and adding dependent packages as needed.
@@ -53,29 +53,127 @@ class UpdaterLogic {
RepoSources sources, RepoSources sources,
Package[] localPkgs) { Package[] localPkgs) {
mSources = sources;
ArrayList<ArchiveInfo> archives = new ArrayList<ArchiveInfo>(); ArrayList<ArchiveInfo> archives = new ArrayList<ArchiveInfo>();
ArrayList<Package> remotePkgs = new ArrayList<Package>(); ArrayList<Package> remotePkgs = new ArrayList<Package>();
RepoSource[] remoteSources = sources.getSources();
if (selectedArchives == null) { if (selectedArchives == null) {
selectedArchives = findUpdates(localPkgs, remotePkgs); selectedArchives = findUpdates(localPkgs, remotePkgs, remoteSources);
} }
for (Archive a : selectedArchives) { for (Archive a : selectedArchives) {
insertArchive(a, archives, selectedArchives, remotePkgs, localPkgs, false); insertArchive(a,
archives,
selectedArchives,
remotePkgs,
remoteSources,
localPkgs,
false /*automated*/);
} }
return archives; return archives;
} }
/**
* Finds new platforms that the user does not have in his/her local SDK
* and adds them to the list of archives to install.
*/
public void addNewPlatforms(ArrayList<ArchiveInfo> archives,
RepoSources sources,
Package[] localPkgs) {
// Find the highest platform installed
float currentPlatformScore = 0;
float currentAddonScore = 0;
HashMap<String, Float> currentExtraScore = new HashMap<String, Float>();
for (Package p : localPkgs) {
int rev = p.getRevision();
int api = 0;
boolean isPreview = false;
if (p instanceof PlatformPackage) {
AndroidVersion vers = ((PlatformPackage) p).getVersion();
api = vers.getApiLevel();
isPreview = vers.isPreview();
} else if (p instanceof AddonPackage) {
AndroidVersion vers = ((AddonPackage) p).getVersion();
api = vers.getApiLevel();
isPreview = vers.isPreview();
} else if (!(p instanceof ExtraPackage)) {
continue;
}
// The score is 10*api + (1 if preview) + rev/100
// This allows previews to rank above a non-preview and
// allows revisions to rank appropriately.
float score = api * 10 + (isPreview ? 1 : 0) + rev/100.f;
if (p instanceof PlatformPackage) {
currentPlatformScore = Math.max(currentPlatformScore, score);
} else if (p instanceof AddonPackage) {
currentAddonScore = Math.max(currentAddonScore, score);
} else if (p instanceof ExtraPackage) {
currentExtraScore.put(((ExtraPackage) p).getPath(), score);
}
}
RepoSource[] remoteSources = sources.getSources();
ArrayList<Package> remotePkgs = new ArrayList<Package>();
fetchRemotePackages(remotePkgs, remoteSources);
for (Package p : remotePkgs) {
int rev = p.getRevision();
int api = 0;
boolean isPreview = false;
if (p instanceof PlatformPackage) {
AndroidVersion vers = ((PlatformPackage) p).getVersion();
api = vers.getApiLevel();
isPreview = vers.isPreview();
} else if (p instanceof AddonPackage) {
AndroidVersion vers = ((AddonPackage) p).getVersion();
api = vers.getApiLevel();
isPreview = vers.isPreview();
} else if (!(p instanceof ExtraPackage)) {
continue;
}
float score = api * 10 + (isPreview ? 1 : 0) + rev/100.f;
boolean shouldAdd = false;
if (p instanceof PlatformPackage) {
shouldAdd = score > currentPlatformScore;
} else if (p instanceof AddonPackage) {
shouldAdd = score > currentAddonScore;
} else if (p instanceof ExtraPackage) {
String key = ((ExtraPackage) p).getPath();
shouldAdd = !currentExtraScore.containsKey(key) ||
score > currentExtraScore.get(key).floatValue();
}
if (shouldAdd) {
// We should suggest this package for installation.
for (Archive a : p.getArchives()) {
if (a.isCompatible()) {
insertArchive(a,
archives,
null /*selectedArchives*/,
remotePkgs,
remoteSources,
localPkgs,
true /*automated*/);
}
}
}
}
}
/** /**
* Find suitable updates to all current local packages. * Find suitable updates to all current local packages.
*/ */
private Collection<Archive> findUpdates(Package[] localPkgs, ArrayList<Package> remotePkgs) { private Collection<Archive> findUpdates(Package[] localPkgs,
ArrayList<Package> remotePkgs,
RepoSource[] remoteSources) {
ArrayList<Archive> updates = new ArrayList<Archive>(); ArrayList<Archive> updates = new ArrayList<Archive>();
fetchRemotePackages(remotePkgs); fetchRemotePackages(remotePkgs, remoteSources);
for (Package localPkg : localPkgs) { for (Package localPkg : localPkgs) {
for (Package remotePkg : remotePkgs) { for (Package remotePkg : remotePkgs) {
@@ -100,6 +198,7 @@ class UpdaterLogic {
ArrayList<ArchiveInfo> outArchives, ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives, Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs, ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
Package[] localPkgs, Package[] localPkgs,
boolean automated) { boolean automated) {
Package p = archive.getParentPackage(); Package p = archive.getParentPackage();
@@ -114,15 +213,32 @@ class UpdaterLogic {
} }
// find dependencies // find dependencies
ArchiveInfo dep = findDependency(p, outArchives, selectedArchives, remotePkgs, localPkgs); ArchiveInfo dep = findDependency(p,
outArchives,
selectedArchives,
remotePkgs,
remoteSources,
localPkgs);
ArchiveInfo ai = new ArchiveInfo( // Make sure it's not a dup
ArchiveInfo ai = null;
for (ArchiveInfo ai2 : outArchives) {
if (ai2.getNewArchive().getParentPackage().sameItemAs(archive.getParentPackage())) {
ai = ai2;
break;
}
}
if (ai == null) {
ai = new ArchiveInfo(
archive, //newArchive archive, //newArchive
updatedArchive, //replaced updatedArchive, //replaced
dep //dependsOn dep //dependsOn
); );
outArchives.add(ai);
}
outArchives.add(ai);
if (dep != null) { if (dep != null) {
dep.addDependencyFor(ai); dep.addDependencyFor(ai);
} }
@@ -134,6 +250,7 @@ class UpdaterLogic {
ArrayList<ArchiveInfo> outArchives, ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives, Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs, ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
Package[] localPkgs) { Package[] localPkgs) {
// Current dependencies can be: // Current dependencies can be:
@@ -144,13 +261,23 @@ class UpdaterLogic {
AddonPackage addon = (AddonPackage) pkg; AddonPackage addon = (AddonPackage) pkg;
return findPlatformDependency( return findPlatformDependency(
addon, outArchives, selectedArchives, remotePkgs, localPkgs); addon,
outArchives,
selectedArchives,
remotePkgs,
remoteSources,
localPkgs);
} else if (pkg instanceof MinToolsPackage) { } else if (pkg instanceof MinToolsPackage) {
MinToolsPackage platformOrExtra = (MinToolsPackage) pkg; MinToolsPackage platformOrExtra = (MinToolsPackage) pkg;
return findToolsDependency( return findToolsDependency(
platformOrExtra, outArchives, selectedArchives, remotePkgs, localPkgs); platformOrExtra,
outArchives,
selectedArchives,
remotePkgs,
remoteSources,
localPkgs);
} }
return null; return null;
@@ -168,6 +295,7 @@ class UpdaterLogic {
ArrayList<ArchiveInfo> outArchives, ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives, Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs, ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
Package[] localPkgs) { Package[] localPkgs) {
// This is the requirement to match. // This is the requirement to match.
int rev = platformOrExtra.getMinToolsRevision(); int rev = platformOrExtra.getMinToolsRevision();
@@ -200,20 +328,22 @@ class UpdaterLogic {
} }
// Otherwise look in the selected archives. // Otherwise look in the selected archives.
for (Archive a : selectedArchives) { if (selectedArchives != null) {
Package p = a.getParentPackage(); for (Archive a : selectedArchives) {
if (p instanceof ToolPackage) { Package p = a.getParentPackage();
if (((ToolPackage) p).getRevision() >= rev) { if (p instanceof ToolPackage) {
// It's not already in the list of things to install, so add it now if (((ToolPackage) p).getRevision() >= rev) {
return insertArchive(a, outArchives, // It's not already in the list of things to install, so add it now
selectedArchives, remotePkgs, localPkgs, return insertArchive(a, outArchives,
true); selectedArchives, remotePkgs, remoteSources, localPkgs,
true /*automated*/);
}
} }
} }
} }
// Finally nothing matched, so let's look at all available remote packages // Finally nothing matched, so let's look at all available remote packages
fetchRemotePackages(remotePkgs); fetchRemotePackages(remotePkgs, remoteSources);
for (Package p : remotePkgs) { for (Package p : remotePkgs) {
if (p instanceof ToolPackage) { if (p instanceof ToolPackage) {
if (((ToolPackage) p).getRevision() >= rev) { if (((ToolPackage) p).getRevision() >= rev) {
@@ -222,8 +352,8 @@ class UpdaterLogic {
for (Archive a : p.getArchives()) { for (Archive a : p.getArchives()) {
if (a.isCompatible()) { if (a.isCompatible()) {
return insertArchive(a, outArchives, return insertArchive(a, outArchives,
selectedArchives, remotePkgs, localPkgs, selectedArchives, remotePkgs, remoteSources, localPkgs,
true); true /*automated*/);
} }
} }
} }
@@ -247,6 +377,7 @@ class UpdaterLogic {
ArrayList<ArchiveInfo> outArchives, ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives, Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs, ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
Package[] localPkgs) { Package[] localPkgs) {
// This is the requirement to match. // This is the requirement to match.
AndroidVersion v = addon.getVersion(); AndroidVersion v = addon.getVersion();
@@ -276,20 +407,22 @@ class UpdaterLogic {
} }
// Otherwise look in the selected archives. // Otherwise look in the selected archives.
for (Archive a : selectedArchives) { if (selectedArchives != null) {
Package p = a.getParentPackage(); for (Archive a : selectedArchives) {
if (p instanceof PlatformPackage) { Package p = a.getParentPackage();
if (v.equals(((PlatformPackage) p).getVersion())) { if (p instanceof PlatformPackage) {
// It's not already in the list of things to install, so add it now if (v.equals(((PlatformPackage) p).getVersion())) {
return insertArchive(a, outArchives, // It's not already in the list of things to install, so add it now
selectedArchives, remotePkgs, localPkgs, return insertArchive(a, outArchives,
true); selectedArchives, remotePkgs, remoteSources, localPkgs,
true /*automated*/);
}
} }
} }
} }
// Finally nothing matched, so let's look at all available remote packages // Finally nothing matched, so let's look at all available remote packages
fetchRemotePackages(remotePkgs); fetchRemotePackages(remotePkgs, remoteSources);
for (Package p : remotePkgs) { for (Package p : remotePkgs) {
if (p instanceof PlatformPackage) { if (p instanceof PlatformPackage) {
if (v.equals(((PlatformPackage) p).getVersion())) { if (v.equals(((PlatformPackage) p).getVersion())) {
@@ -298,8 +431,8 @@ class UpdaterLogic {
for (Archive a : p.getArchives()) { for (Archive a : p.getArchives()) {
if (a.isCompatible()) { if (a.isCompatible()) {
return insertArchive(a, outArchives, return insertArchive(a, outArchives,
selectedArchives, remotePkgs, localPkgs, selectedArchives, remotePkgs, remoteSources, localPkgs,
true); true /*automated*/);
} }
} }
} }
@@ -315,14 +448,11 @@ class UpdaterLogic {
} }
/** Fetch all remote packages only if really needed. */ /** Fetch all remote packages only if really needed. */
protected void fetchRemotePackages(ArrayList<Package> remotePkgs) { protected void fetchRemotePackages(ArrayList<Package> remotePkgs, RepoSource[] remoteSources) {
if (remotePkgs.size() > 0) { if (remotePkgs.size() > 0) {
return; return;
} }
// Get all the available packages from all loaded sources
RepoSource[] remoteSources = mSources.getSources();
for (RepoSource remoteSrc : remoteSources) { for (RepoSource remoteSrc : remoteSources) {
Package[] pkgs = remoteSrc.getPackages(); Package[] pkgs = remoteSrc.getPackages();
if (pkgs != null) { if (pkgs != null) {

View File

@@ -60,7 +60,11 @@ public class UpdaterWindowImpl {
private ArrayList<Object[]> mExtraPages; private ArrayList<Object[]> mExtraPages;
/** A factory to create progress task dialogs. */ /** A factory to create progress task dialogs. */
private ProgressTaskFactory mTaskFactory; private ProgressTaskFactory mTaskFactory;
/** The initial page to display. If null or not a know class, the first page will be displayed.
* Must be set before the first call to {@link #open()}. */
private Class<? extends Composite> mInitialPage;
/** Sets whether the auto-update wizard will be shown when opening the window. */
private boolean mRequestAutoUpdate;
// --- UI members --- // --- UI members ---
@@ -148,7 +152,7 @@ public class UpdaterWindowImpl {
// Hide everything down-below from SWT designer // Hide everything down-below from SWT designer
//$hide>>$ //$hide>>$
// --- UI Callbacks ----------- // --- Public API -----------
/** /**
@@ -169,14 +173,42 @@ public class UpdaterWindowImpl {
mExtraPages.add(new Object[]{ title, pageClass }); mExtraPages.add(new Object[]{ title, pageClass });
} }
/**
* Indicate the initial page that should be selected when the window opens.
* This must be called before the call to {@link #open()}.
* If null or if the page class is not found, the first page will be selected.
*/
public void setInitialPage(Class<? extends Composite> pageClass) {
mInitialPage = pageClass;
}
/**
* Sets whether the auto-update wizard will be shown when opening the window.
* <p/>
* This must be called before the call to {@link #open()}.
*/
public void setRequestAutoUpdate(boolean requestAutoUpdate) {
mRequestAutoUpdate = requestAutoUpdate;
}
/**
* Adds a new listener to be notified when a change is made to the content of the SDK.
*/
public void addListeners(ISdkListener listener) { public void addListeners(ISdkListener listener) {
mUpdaterData.addListeners(listener); mUpdaterData.addListeners(listener);
} }
/**
* Removes a new listener to be notified anymore when a change is made to the content of
* the SDK.
*/
public void removeListener(ISdkListener listener) { public void removeListener(ISdkListener listener) {
mUpdaterData.removeListener(listener); mUpdaterData.removeListener(listener);
} }
// --- Internals & UI Callbacks -----------
/** /**
* Helper to return the SWT shell. * Helper to return the SWT shell.
*/ */
@@ -230,12 +262,25 @@ public class UpdaterWindowImpl {
addPage(mRemotePackagesPage, "Available Packages"); addPage(mRemotePackagesPage, "Available Packages");
addExtraPages(); addExtraPages();
displayPage(0); int pageIndex = 0;
mPageList.setSelection(0); int i = 0;
for (Composite p : mPages) {
if (p.getClass().equals(mInitialPage)) {
pageIndex = i;
break;
}
i++;
}
displayPage(pageIndex);
mPageList.setSelection(pageIndex);
setupSources(); setupSources();
initializeSettings(); initializeSettings();
mUpdaterData.notifyListeners(); mUpdaterData.notifyListeners();
if (mRequestAutoUpdate) {
mUpdaterData.updateOrInstallAll(null /*selectedArchives*/);
}
} }
/** /**

View File

@@ -69,6 +69,25 @@ public class UpdaterWindow {
mWindow.registerExtraPage(title, pageClass); mWindow.registerExtraPage(title, pageClass);
} }
/**
* Indicate the initial page that should be selected when the window opens.
* <p/>
* This must be called before the call to {@link #open()}.
* If null or if the page class is not found, the first page will be selected.
*/
public void setInitialPage(Class<? extends Composite> pageClass) {
mWindow.setInitialPage(pageClass);
}
/**
* Sets whether the auto-update wizard will be shown when opening the window.
* <p/>
* This must be called before the call to {@link #open()}.
*/
public void setRequestAutoUpdate(boolean requestAutoUpdate) {
mWindow.setRequestAutoUpdate(requestAutoUpdate);
}
/** /**
* Adds a new listener to be notified when a change is made to the content of the SDK. * Adds a new listener to be notified when a change is made to the content of the SDK.
*/ */

View File

@@ -21,6 +21,7 @@ import com.android.sdklib.internal.repository.MockAddonPackage;
import com.android.sdklib.internal.repository.MockPlatformPackage; import com.android.sdklib.internal.repository.MockPlatformPackage;
import com.android.sdklib.internal.repository.MockToolPackage; import com.android.sdklib.internal.repository.MockToolPackage;
import com.android.sdklib.internal.repository.Package; import com.android.sdklib.internal.repository.Package;
import com.android.sdklib.internal.repository.RepoSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -37,7 +38,10 @@ public class UpdaterLogicTest extends TestCase {
} }
@Override @Override
protected void fetchRemotePackages(ArrayList<Package> remotePkgs) { protected void fetchRemotePackages(ArrayList<Package> remotePkgs,
RepoSource[] remoteSources) {
// Ignore remoteSources and instead uses the remotePackages list given to the
// constructor.
if (mRemotePackages != null) { if (mRemotePackages != null) {
remotePkgs.addAll(Arrays.asList(mRemotePackages)); remotePkgs.addAll(Arrays.asList(mRemotePackages));
} }
@@ -59,13 +63,14 @@ public class UpdaterLogicTest extends TestCase {
// a2 depends on p2, which is not in the locals // a2 depends on p2, which is not in the locals
Package[] locals = { p1, a1 }; Package[] locals = { p1, a1 };
assertNull(mul.findPlatformDependency(a2, out, selected, remote, locals)); RepoSource[] sources = null;
assertNull(mul.findPlatformDependency(a2, out, selected, remote, sources, locals));
assertEquals(0, out.size()); assertEquals(0, out.size());
// p2 is now selected, and should be scheduled for install in out // p2 is now selected, and should be scheduled for install in out
Archive p2_archive = p2.getArchives()[0]; Archive p2_archive = p2.getArchives()[0];
selected.add(p2_archive); selected.add(p2_archive);
ArchiveInfo ai2 = mul.findPlatformDependency(a2, out, selected, remote, locals); ArchiveInfo ai2 = mul.findPlatformDependency(a2, out, selected, remote, sources, locals);
assertNotNull(ai2); assertNotNull(ai2);
assertSame(p2_archive, ai2.getNewArchive()); assertSame(p2_archive, ai2.getNewArchive());
assertEquals(1, out.size()); assertEquals(1, out.size());
@@ -86,13 +91,14 @@ public class UpdaterLogicTest extends TestCase {
// p2 depends on t2, which is not locally installed // p2 depends on t2, which is not locally installed
Package[] locals = { t1 }; Package[] locals = { t1 };
assertNull(mul.findToolsDependency(p2, out, selected, remote, locals)); RepoSource[] sources = null;
assertNull(mul.findToolsDependency(p2, out, selected, remote, sources, locals));
assertEquals(0, out.size()); assertEquals(0, out.size());
// t2 is now selected and can be used as a dependency // t2 is now selected and can be used as a dependency
Archive t2_archive = t2.getArchives()[0]; Archive t2_archive = t2.getArchives()[0];
selected.add(t2_archive); selected.add(t2_archive);
ArchiveInfo ai2 = mul.findToolsDependency(p2, out, selected, remote, locals); ArchiveInfo ai2 = mul.findToolsDependency(p2, out, selected, remote, sources, locals);
assertNotNull(ai2); assertNotNull(ai2);
assertSame(t2_archive, ai2.getNewArchive()); assertSame(t2_archive, ai2.getNewArchive());
assertEquals(1, out.size()); assertEquals(1, out.size());