aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java46
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/FragmentMenu.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ListViewTypeMenu.java2
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java117
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java25
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/AvdManagerAction.java7
-rw-r--r--ide_common/src/com/android/ide/common/resources/ResourceRepository.java3
-rw-r--r--sdkmanager/app/src/com/android/sdkmanager/Main.java7
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/StdSdkLog.java49
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AdtUpdateDialog.java5
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/IUpdaterWindow.java (renamed from sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/IUpdaterWindow.java)7
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/MenuBarWrapper.java56
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/PackagesPage.java39
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java10
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl2.java186
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java93
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java7
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java47
18 files changed, 480 insertions, 228 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
index 9b960cb..118e70a 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
@@ -33,6 +33,7 @@ import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
@@ -89,7 +90,7 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
.getAdapter(IProject.class);
}
if (project != null) {
- updateProject(project);
+ install(project, false /* waitForFinish */);
}
}
}
@@ -99,7 +100,16 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
mSelection = selection;
}
- private void updateProject(final IProject project) {
+ /**
+ * Install the compatibility jar into the given project.
+ *
+ * @param project The Android project to install the compatibility jar into
+ * @param waitForFinish If true, block until the task has finished
+ * @return true if the installation was successful (or if <code>waitForFinish</code>
+ * is false, if the installation is likely to be successful - e.g. the user has
+ * at least agreed to all installation prompts.)
+ */
+ public static boolean install(final IProject project, boolean waitForFinish) {
final IJavaProject javaProject = JavaCore.create(project);
if (javaProject == null) {
@@ -110,9 +120,9 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
final Sdk sdk = Sdk.getCurrent();
if (sdk == null) {
AdtPlugin.printErrorToConsole(
- this.getClass().getSimpleName(), // tag
+ AddCompatibilityJarAction.class.getSimpleName(), // tag
"Error: Android SDK is not loaded yet."); //$NON-NLS-1$
- return;
+ return false;
}
// TODO: For the generic action, check the library isn't in the project already.
@@ -130,7 +140,7 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
if (!result.getFirst().booleanValue()) {
AdtPlugin.printErrorToConsole("Failed to install Android Compatibility library");
- return;
+ return false;
}
// TODO these "v4" values needs to be dynamic, e.g. we could try to match
@@ -143,12 +153,12 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
if (!jarPath.isFile()) {
AdtPlugin.printErrorToConsole("Android Compatibility JAR not found:",
jarPath.getAbsolutePath());
- return;
+ return false;
}
// Then run an Eclipse asynchronous job to update the project
- new Job("Add Compatibility Library to Project") {
+ Job job = new Job("Add Compatibility Library to Project") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
@@ -183,10 +193,22 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
}
}
}
- }.schedule();
+ };
+ job.schedule();
+
+ if (waitForFinish) {
+ try {
+ job.join();
+ return job.getState() == IStatus.OK;
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+
+ return true;
}
- private IResource copyJarIntoProject(
+ private static IResource copyJarIntoProject(
IProject project,
File jarPath,
IProgressMonitor monitor) throws IOException, CoreException {
@@ -202,6 +224,8 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
// Only modify the file if necessary so that we don't trigger unnecessary recompilations
if (!destPath.isFile() || !isSameFile(jarPath, destPath)) {
copyFile(jarPath, destPath);
+ // Make sure Eclipse discovers java.io file changes
+ resFolder.refreshLocal(1, new NullProgressMonitor());
}
return destFile;
@@ -213,7 +237,7 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
* @param source the source file to copy
* @param destination the destination file to write
*/
- private boolean isSameFile(File source, File destination) throws IOException {
+ private static boolean isSameFile(File source, File destination) throws IOException {
if (source.length() != destination.length()) {
return false;
@@ -273,7 +297,7 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
* @param source the source file to copy
* @param destination the destination file to write
*/
- private void copyFile(File source, File destination) throws IOException {
+ private static void copyFile(File source, File destination) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/FragmentMenu.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/FragmentMenu.java
index bb519fb..a43eaff 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/FragmentMenu.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/FragmentMenu.java
@@ -289,7 +289,7 @@ public class FragmentMenu extends SubmenuAction {
if (validator != null) {
// Ensure wide enough to accommodate validator error message
- dlg.setSize(70, 10);
+ dlg.setSize(85, 10);
dlg.setInputValidator(validator);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ListViewTypeMenu.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ListViewTypeMenu.java
index b90b869..c1c5e5a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ListViewTypeMenu.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ListViewTypeMenu.java
@@ -168,7 +168,7 @@ public class ListViewTypeMenu extends SubmenuAction {
if (validator != null) {
// Ensure wide enough to accommodate validator error message
- dlg.setSize(70, 10);
+ dlg.setSize(85, 10);
dlg.setInputValidator(validator);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
index 2d0dc66..fbe2957 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
@@ -35,6 +35,7 @@ import com.android.ide.common.api.Point;
import com.android.ide.common.layout.ViewRule;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
@@ -43,6 +44,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SimpleElement;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.resources.CyclicDependencyValidator;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
@@ -60,9 +62,10 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
@@ -70,16 +73,24 @@ import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction;
import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor;
import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension;
-import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.SelectionDialog;
@@ -94,6 +105,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/**
* The rule engine manages the layout rules and interacts with them.
@@ -926,7 +938,7 @@ public class RulesEngine {
if (validator != null) {
// Ensure wide enough to accommodate validator error message
- dlg.setSize(70, 10);
+ dlg.setSize(85, 10);
dlg.setInputValidator(validator);
}
@@ -988,7 +1000,7 @@ public class RulesEngine {
// Compute a search scope: We need to merge all the subclasses
// android.app.Fragment and android.support.v4.app.Fragment
IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
- IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
+ final IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
if (javaProject != null) {
IType oldFragmentType = javaProject.findType(CLASS_V4_FRAGMENT);
@@ -997,23 +1009,26 @@ public class RulesEngine {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
if (target.getVersion().getApiLevel() < 11 && oldFragmentType == null) {
// Compatibility library must be present
- Status status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, 0,
- "Fragments require API level 11 or higher, or a compatibility "
- + "library for older versions.\n\n"
- + "Please install the \"Android Compatibility Package\" from "
- + "the SDK manager and add its .jar file "
- + "(extras/android/compatibility/v4/android-support-v4.jar) "
- + "to the project's "
- + " Java Build Path.", null);
- ErrorDialog.openError(Display.getCurrent().getActiveShell(),
- "Fragment Warning", null, status);
-
- // TODO: Offer to automatically perform configuration for the user;
- // either upgrade project to require API 11, or first install the
- // compatibility library via the SDK manager and then adding
- // ${SDK_HOME}/extras/android/compatibility/v4/android-support-v4.jar
- // to the project jar dependencies.
- return null;
+ MessageDialog dialog =
+ new MessageDialog(
+ Display.getCurrent().getActiveShell(),
+ "Fragment Warning",
+ null,
+ "Fragments require API level 11 or higher, or a compatibility "
+ + "library for older versions.\n\n"
+ + " Do you want to install the compatibility library?",
+ MessageDialog.QUESTION,
+ new String[] { "Install", "Cancel" },
+ 1 /* default button: Cancel */);
+ int answer = dialog.open();
+ if (answer == 0) {
+ if (!AddCompatibilityJarAction.install(mProject,
+ true /*waitForFinish*/)) {
+ return null;
+ }
+ } else {
+ return null;
+ }
}
// Look up sub-types of each (new fragment class and compatibility fragment
@@ -1040,7 +1055,11 @@ public class RulesEngine {
}
Shell parent = AdtPlugin.getDisplay().getActiveShell();
- SelectionDialog dialog = JavaUI.createTypeDialog(
+ final AtomicReference<String> returnValue =
+ new AtomicReference<String>();
+ final AtomicReference<SelectionDialog> dialogHolder =
+ new AtomicReference<SelectionDialog>();
+ final SelectionDialog dialog = JavaUI.createTypeDialog(
parent,
new ProgressMonitorDialog(parent),
scope,
@@ -1049,6 +1068,25 @@ public class RulesEngine {
"?", //$NON-NLS-1$
new TypeSelectionExtension() {
@Override
+ public Control createContentArea(Composite parentComposite) {
+ Composite composite = new Composite(parentComposite, SWT.NONE);
+ composite.setLayout(new GridLayout(1, false));
+ Button button = new Button(composite, SWT.PUSH);
+ button.setText("Create New...");
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String fqcn = createNewFragmentClass(javaProject);
+ if (fqcn != null) {
+ returnValue.set(fqcn);
+ dialogHolder.get().close();
+ }
+ }
+ });
+ return composite;
+ }
+
+ @Override
public ITypeInfoFilterExtension getFilterExtension() {
return new ITypeInfoFilterExtension() {
public boolean select(ITypeInfoRequestor typeInfoRequestor) {
@@ -1063,12 +1101,16 @@ public class RulesEngine {
};
}
});
+ dialogHolder.set(dialog);
dialog.setTitle("Choose Fragment Class");
dialog.setMessage("Select a Fragment class (? = any character, * = any string):");
if (dialog.open() == IDialogConstants.CANCEL_ID) {
return null;
}
+ if (returnValue.get() != null) {
+ return returnValue.get();
+ }
Object[] types = dialog.getResult();
if (types != null && types.length > 0) {
@@ -1082,4 +1124,35 @@ public class RulesEngine {
return null;
}
}
+
+ private String createNewFragmentClass(IJavaProject javaProject) {
+ NewClassWizardPage page = new NewClassWizardPage();
+
+ IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
+ String superClass;
+ if (target.getVersion().getApiLevel() < 11) {
+ superClass = CLASS_V4_FRAGMENT;
+ } else {
+ superClass = CLASS_FRAGMENT;
+ }
+ page.setSuperClass(superClass, true /* canBeModified */);
+ IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject);
+ if (root != null) {
+ page.setPackageFragmentRoot(root, true /* canBeModified */);
+ }
+ ManifestInfo manifestInfo = ManifestInfo.get(mProject);
+ IPackageFragment pkg = manifestInfo.getPackageFragment();
+ if (pkg != null) {
+ page.setPackageFragment(pkg, true /* canBeModified */);
+ }
+ OpenNewClassWizardAction action = new OpenNewClassWizardAction();
+ action.setConfiguredWizardPage(page);
+ action.run();
+ IType createdType = page.getCreatedType();
+ if (createdType != null) {
+ return createdType.getFullyQualifiedName();
+ } else {
+ return null;
+ }
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
index 0feab55..475f5a7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
@@ -52,6 +52,7 @@ import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchScope;
@@ -330,6 +331,28 @@ public class ManifestInfo {
}
/**
+ * Returns the {@link IPackageFragment} for the package registered in the manifest
+ *
+ * @return the {@link IPackageFragment} for the package registered in the manifest
+ */
+ public IPackageFragment getPackageFragment() {
+ sync();
+ try {
+ IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
+ if (javaProject != null) {
+ IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject);
+ if (root != null) {
+ return root.getPackageFragment(mPackage);
+ }
+ }
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
+
+ return null;
+ }
+
+ /**
* Returns the activity associated with the given layout file. Makes an educated guess
* by peeking at the usages of the R.layout.name field corresponding to the layout and
* if it finds a usage.
@@ -540,7 +563,7 @@ public class ManifestInfo {
}
/** Returns the first package root for the given java project */
- private static IPackageFragmentRoot getSourcePackageRoot(IJavaProject javaProject) {
+ public static IPackageFragmentRoot getSourcePackageRoot(IJavaProject javaProject) {
IPackageFragmentRoot packageRoot = null;
List<IPath> sources = BaseProjectHelper.getSourceClasspaths(javaProject);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/AvdManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/AvdManagerAction.java
index 42739e2..ded5919 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/AvdManagerAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/AvdManagerAction.java
@@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.sdkuilib.repository.ISdkChangeListener;
import com.android.sdkuilib.repository.UpdaterWindow;
+import com.android.sdkuilib.repository.UpdaterWindow.InvocationContext;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
@@ -45,7 +46,7 @@ public class AvdManagerAction implements IWorkbenchWindowActionDelegate, IObject
}
public void run(IAction action) {
- Sdk sdk = Sdk.getCurrent();
+ final Sdk sdk = Sdk.getCurrent();
if (sdk != null) {
// Runs the updater window, directing all logs to the ADT console.
@@ -53,7 +54,8 @@ public class AvdManagerAction implements IWorkbenchWindowActionDelegate, IObject
UpdaterWindow window = new UpdaterWindow(
AdtPlugin.getDisplay().getActiveShell(),
new AdtConsoleSdkLog(),
- sdk.getSdkLocation());
+ sdk.getSdkLocation(),
+ InvocationContext.IDE);
ISdkChangeListener listener = new ISdkChangeListener() {
public void onSdkLoaded() {
@@ -88,7 +90,6 @@ public class AvdManagerAction implements IWorkbenchWindowActionDelegate, IObject
// then we want to make sure we don't get any attempt to use the SDK
// before the postInstallHook is called.
- Sdk sdk = Sdk.getCurrent();
if (sdk != null) {
DexWrapper dx = sdk.getDexWrapper();
dx.unload();
diff --git a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
index 41e4f89..f72ebd2 100644
--- a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
+++ b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
@@ -482,10 +482,11 @@ public abstract class ResourceRepository {
*/
private Map<String, ResourceValue> getConfiguredResource(ResourceType type,
FolderConfiguration referenceConfig) {
+
// get the resource item for the given type
List<ResourceItem> items = mResourceMap.get(type);
if (items == null) {
- return Collections.emptyMap();
+ return new HashMap<String, ResourceValue>();
}
// create the map
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java
index d3e3235..ccac9b7 100644
--- a/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -43,8 +43,8 @@ import com.android.sdkuilib.internal.repository.PackagesPage;
import com.android.sdkuilib.internal.repository.UpdateNoWindow;
import com.android.sdkuilib.internal.repository.UpdaterPage;
import com.android.sdkuilib.internal.widgets.MessageBoxLog;
-import com.android.sdkuilib.repository.IUpdaterWindow;
import com.android.sdkuilib.repository.UpdaterWindow;
+import com.android.sdkuilib.repository.UpdaterWindow.InvocationContext;
import com.android.util.Pair;
import org.eclipse.swt.widgets.Display;
@@ -312,10 +312,11 @@ public class Main {
Display.getCurrent(),
true /*logErrorsOnly*/);
- IUpdaterWindow window = new UpdaterWindow(
+ UpdaterWindow window = new UpdaterWindow(
null /* parentShell */,
errorLogger,
- mOsSdkFolder);
+ mOsSdkFolder,
+ InvocationContext.STANDALONE);
window.registerPage(SettingsPage.class, UpdaterPage.Purpose.SETTINGS);
window.registerPage(AboutPage.class, UpdaterPage.Purpose.ABOUT_BOX);
if (autoUpdate) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/StdSdkLog.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/StdSdkLog.java
index 1683808..71ce0ad 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/StdSdkLog.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/StdSdkLog.java
@@ -28,24 +28,57 @@ public class StdSdkLog implements ISdkLog {
public void error(Throwable t, String errorFormat, Object... args) {
if (errorFormat != null) {
- System.err.printf("Error: " + errorFormat, args);
- if (!errorFormat.endsWith("\n")) {
- System.err.printf("\n");
+ String msg = String.format("Error: " + errorFormat, args);
+
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS &&
+ !msg.endsWith("\r\n") &&
+ msg.endsWith("\n")) {
+ // remove last \n so that println can use \r\n as needed.
+ msg = msg.substring(0, msg.length() - 1);
+ }
+
+ System.err.print(msg);
+
+ if (!msg.endsWith("\n")) {
+ System.err.println();
}
}
if (t != null) {
- System.err.printf("Error: %s\n", t.getMessage());
+ System.err.println(String.format("Error: %1$s%2$s", t.getMessage()));
}
}
public void warning(String warningFormat, Object... args) {
- System.out.printf("Warning: " + warningFormat, args);
- if (!warningFormat.endsWith("\n")) {
- System.out.printf("\n");
+ String msg = String.format("Warning: " + warningFormat, args);
+
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS &&
+ !msg.endsWith("\r\n") &&
+ msg.endsWith("\n")) {
+ // remove last \n so that println can use \r\n as needed.
+ msg = msg.substring(0, msg.length() - 1);
+ }
+
+ System.out.print(msg);
+
+ if (!msg.endsWith("\n")) {
+ System.out.println();
}
}
public void printf(String msgFormat, Object... args) {
- System.out.printf(msgFormat, args);
+ String msg = String.format(msgFormat, args);
+
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS &&
+ !msg.endsWith("\r\n") &&
+ msg.endsWith("\n")) {
+ // remove last \n so that println can use \r\n as needed.
+ msg = msg.substring(0, msg.length() - 1);
+ }
+
+ System.out.print(msg);
+
+ if (!msg.endsWith("\n")) {
+ System.out.println();
+ }
}
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AdtUpdateDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AdtUpdateDialog.java
index 911b3a5..0b4879b 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AdtUpdateDialog.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AdtUpdateDialog.java
@@ -150,7 +150,10 @@ public class AdtUpdateDialog extends SwtBaseDialog {
protected void postCreate() {
ProgressViewFactory factory = new ProgressViewFactory();
factory.setProgressView(new ProgressView(
- mStatusText, mProgressBar, null /*buttonStop*/));
+ mStatusText,
+ mProgressBar,
+ null /*buttonStop*/,
+ mUpdaterData.getSdkLog()));
mUpdaterData.setTaskFactory(factory);
setupSources();
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/IUpdaterWindow.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/IUpdaterWindow.java
index def5de0..2bfff2a 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/IUpdaterWindow.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/IUpdaterWindow.java
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.sdkuilib.repository;
+package com.android.sdkuilib.internal.repository;
-import com.android.sdkuilib.internal.repository.UpdaterPage;
+import com.android.sdkuilib.repository.ISdkChangeListener;
import org.eclipse.swt.widgets.Composite;
+/**
+ * Interface for the actual implementation of the Update Window.
+ */
public interface IUpdaterWindow {
/**
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/MenuBarWrapper.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/MenuBarWrapper.java
new file mode 100755
index 0000000..eabe603
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/MenuBarWrapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdkuilib.internal.repository;
+
+
+import com.android.menubar.IMenuBarCallback;
+import com.android.menubar.MenuBarEnhancer;
+
+import org.eclipse.swt.widgets.Menu;
+
+/**
+ * A simple wrapper/delegate around the {@link MenuBarEnhancer}.
+ *
+ * The {@link MenuBarEnhancer} and {@link IMenuBarCallback} classes are only
+ * available when the SwtMenuBar library is available too. This wrapper helps
+ * {@link UpdaterWindowImpl2} make the call conditional, otherwise the updater
+ * window class would fail to load when the SwtMenuBar library isn't found.
+ */
+abstract class MenuBarWrapper {
+
+ public MenuBarWrapper(String appName, Menu menu) {
+ MenuBarEnhancer.setupMenu(appName, menu, new IMenuBarCallback() {
+ public void onPreferencesMenuSelected() {
+ MenuBarWrapper.this.onPreferencesMenuSelected();
+ }
+
+ public void onAboutMenuSelected() {
+ MenuBarWrapper.this.onAboutMenuSelected();
+ }
+
+ public void printError(String format, Object... args) {
+ MenuBarWrapper.this.printError(format, args);
+ }
+ });
+ }
+
+ abstract public void onPreferencesMenuSelected();
+
+ abstract public void onAboutMenuSelected();
+
+ abstract public void printError(String format, Object... args);
+}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/PackagesPage.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/PackagesPage.java
index a0eadbb..5fc9881 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/PackagesPage.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/PackagesPage.java
@@ -96,7 +96,7 @@ public class PackagesPage extends UpdaterPage
enum MenuAction {
RELOAD (SWT.NONE, "Reload"),
SHOW_ADDON_SITES (SWT.NONE, "Manage Sources..."),
- TOGGLE_SHOW_ARCHIVES (SWT.CHECK, "Show Archives"),
+ TOGGLE_SHOW_ARCHIVES (SWT.CHECK, "Show Archives Details"),
TOGGLE_SHOW_INSTALLED_PKG (SWT.CHECK, "Show Installed Packages"),
TOGGLE_SHOW_OBSOLETE_PKG (SWT.CHECK, "Show Obsolete Packages"),
TOGGLE_SHOW_UPDATE_NEW_PKG (SWT.CHECK, "Show Updates/New Packages"),
@@ -919,7 +919,8 @@ public class PackagesPage extends UpdaterPage
}
} else {
// In non-detail mode, we install all the compatible archives
- // found in the selected pkg items or update packages.
+ // found in the selected pkg items. We also automatically
+ // select update packages rather than the root package if any.
Object[] checked = mTreeViewer.getCheckedElements();
if (checked != null) {
@@ -930,6 +931,15 @@ public class PackagesPage extends UpdaterPage
p = (Package) c;
} else if (c instanceof PkgItem) {
p = ((PkgItem) c).getPackage();
+
+ PkgItem pi = (PkgItem) c;
+ if (pi.getState() == PkgState.HAS_UPDATE) {
+ List<Package> updates = pi.getUpdatePkgs();
+ // If there's one and only one update, auto-select it instead.
+ if (updates != null && updates.size() == 1) {
+ p = updates.get(0);
+ }
+ }
}
if (p != null) {
for (Archive a : p.getArchives()) {
@@ -1073,9 +1083,17 @@ public class PackagesPage extends UpdaterPage
case INSTALLED:
return "Installed";
case HAS_UPDATE:
- return "Update available";
+ List<Package> updates = pkg.getUpdatePkgs();
+ if (updates.size() == 1) {
+ return String.format("Update available: rev. %1$s",
+ updates.get(0).getRevision());
+ } else {
+ // This case should not happen in *our* typical release workflow.
+ return "Multiple updates available";
+ }
case NEW:
- return "Not installed. New revision " + Integer.toString(pkg.getRevision());
+ return "Not installed";
+ // TODO display pkg.getRevision() in a tooltip
}
return pkg.getState().toString();
@@ -1158,7 +1176,10 @@ public class PackagesPage extends UpdaterPage
} else if (parentElement instanceof PkgItem) {
List<Package> pkgs = ((PkgItem) parentElement).getUpdatePkgs();
- if (pkgs != null) {
+
+ // Display update packages as sub-items if there's more than one
+ // or if the archive/details mode is activated.
+ if (pkgs != null && (pkgs.size() > 1 || mDisplayArchives)) {
return pkgs.toArray();
}
@@ -1177,7 +1198,8 @@ public class PackagesPage extends UpdaterPage
}
public Object getParent(Object element) {
- // TODO Auto-generated method stub
+ // Pass. We don't try to compute the parent element and so far
+ // that doesn't seem to affect the behavior of the tree widget.
return null;
}
@@ -1190,7 +1212,10 @@ public class PackagesPage extends UpdaterPage
} else if (parentElement instanceof PkgItem) {
List<Package> pkgs = ((PkgItem) parentElement).getUpdatePkgs();
- if (pkgs != null) {
+
+ // Display update packages as sub-items if there's more than one
+ // or if the archive/details mode is activated.
+ if (pkgs != null && (pkgs.size() > 1 || mDisplayArchives)) {
return !pkgs.isEmpty();
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java
index b148b4e..7a7cc6d 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java
@@ -23,7 +23,7 @@ import com.android.sdkuilib.internal.repository.UpdaterPage.Purpose;
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
import com.android.sdkuilib.internal.tasks.ProgressTaskFactory;
import com.android.sdkuilib.repository.ISdkChangeListener;
-import com.android.sdkuilib.repository.IUpdaterWindow;
+import com.android.sdkuilib.repository.UpdaterWindow.InvocationContext;
import com.android.util.Pair;
import org.eclipse.swt.SWT;
@@ -87,8 +87,14 @@ public class UpdaterWindowImpl implements IUpdaterWindow {
* @param parentShell Parent shell.
* @param sdkLog Logger. Cannot be null.
* @param osSdkRoot The OS path to the SDK root.
+ * @param context The {@link InvocationContext} to change the behavior depending on who's
+ * opening the SDK Manager. Unused for SdkMan1.
*/
- public UpdaterWindowImpl(Shell parentShell, ISdkLog sdkLog, String osSdkRoot) {
+ public UpdaterWindowImpl(
+ Shell parentShell,
+ ISdkLog sdkLog,
+ String osSdkRoot,
+ InvocationContext context/*unused*/) {
mParentShell = parentShell;
mUpdaterData = new UpdaterData(osSdkRoot, sdkLog);
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl2.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl2.java
index 43ec7cc..dda5b36 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl2.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl2.java
@@ -17,8 +17,6 @@
package com.android.sdkuilib.internal.repository;
-import com.android.menubar.IMenuBarCallback;
-import com.android.menubar.MenuBarEnhancer;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
import com.android.sdkuilib.internal.repository.PackagesPage.MenuAction;
@@ -26,20 +24,18 @@ import com.android.sdkuilib.internal.repository.UpdaterPage.Purpose;
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
import com.android.sdkuilib.internal.tasks.ProgressView;
import com.android.sdkuilib.internal.tasks.ProgressViewFactory;
+import com.android.sdkuilib.internal.widgets.ImgDisabledButton;
+import com.android.sdkuilib.internal.widgets.ToggleButton;
import com.android.sdkuilib.repository.ISdkChangeListener;
-import com.android.sdkuilib.repository.IUpdaterWindow;
+import com.android.sdkuilib.repository.UpdaterWindow.InvocationContext;
import com.android.sdkuilib.ui.GridDataBuilder;
import com.android.sdkuilib.ui.GridLayoutBuilder;
import com.android.sdkuilib.ui.SwtBaseDialog;
import com.android.util.Pair;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
@@ -69,6 +65,7 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
private static final String APP_NAME = "Android SDK Manager";
private final Shell mParentShell;
+ private final InvocationContext mContext;
/** Internal data shared between the window and its pages. */
private final UpdaterData mUpdaterData;
/** A list of extra pages to instantiate. Each entry is an object array with 2 elements:
@@ -93,9 +90,16 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
* @param parentShell Parent shell.
* @param sdkLog Logger. Cannot be null.
* @param osSdkRoot The OS path to the SDK root.
+ * @param context The {@link InvocationContext} to change the behavior depending on who's
+ * opening the SDK Manager.
*/
- public UpdaterWindowImpl2(Shell parentShell, ISdkLog sdkLog, String osSdkRoot) {
+ public UpdaterWindowImpl2(
+ Shell parentShell,
+ ISdkLog sdkLog,
+ String osSdkRoot,
+ InvocationContext context) {
mParentShell = parentShell;
+ mContext = context;
mUpdaterData = new UpdaterData(osSdkRoot, sdkLog);
}
@@ -255,8 +259,10 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
Menu menuTools = new Menu(menuBarTools);
menuBarTools.setMenu(menuTools);
- MenuItem manageAvds = new MenuItem(menuTools, SWT.NONE);
- manageAvds.setText("Manage AVDs...");
+ if (mContext == InvocationContext.STANDALONE) {
+ MenuItem manageAvds = new MenuItem(menuTools, SWT.NONE);
+ manageAvds.setText("Manage AVDs...");
+ }
MenuItem manageSources = new MenuItem(menuTools,
MenuAction.SHOW_ADDON_SITES.getMenuStyle());
@@ -265,23 +271,32 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
mPkgPage.registerMenuAction(
MenuAction.SHOW_ADDON_SITES, manageSources);
- MenuBarEnhancer.setupMenu(APP_NAME, menuTools, new IMenuBarCallback() {
- public void onPreferencesMenuSelected() {
- showRegisteredPage(Purpose.SETTINGS);
- }
+ if (mContext == InvocationContext.STANDALONE) {
+ // Note: when invoked from an IDE, the SwtMenuBar library isn't
+ // available. This means this source should not directly import
+ // any of SwtMenuBar classes, otherwise the whole window class
+ // would fail to load. The MenuBarWrapper below helps to make
+ // that indirection.
- public void onAboutMenuSelected() {
- showRegisteredPage(Purpose.ABOUT_BOX);
- }
+ new MenuBarWrapper(APP_NAME, menuTools) {
+ @Override
+ public void onPreferencesMenuSelected() {
+ showRegisteredPage(Purpose.SETTINGS);
+ }
- public void printError(String format, Object... args) {
- if (mUpdaterData != null) {
- // TODO: right now dump to stderr. Use sdklog later.
- //mUpdaterData.getSdkLog().error(null, format, args);
- System.err.printf(format, args);
+ @Override
+ public void onAboutMenuSelected() {
+ showRegisteredPage(Purpose.ABOUT_BOX);
}
- }
- });
+
+ @Override
+ public void printError(String format, Object... args) {
+ if (mUpdaterData != null) {
+ mUpdaterData.getSdkLog().error(null, format, args);
+ }
+ }
+ };
+ }
}
private Image getImage(String filename) {
@@ -378,7 +393,8 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
private boolean postCreateContent() {
ProgressViewFactory factory = new ProgressViewFactory();
factory.setProgressView(new ProgressView(
- mStatusText, mProgressBar, mButtonStop));
+ mStatusText, mProgressBar, mButtonStop,
+ mContext == InvocationContext.IDE ? mUpdaterData.getSdkLog() : null));
mUpdaterData.setTaskFactory(factory);
setWindowImage(mShell);
@@ -495,126 +511,6 @@ public class UpdaterWindowImpl2 implements IUpdaterWindow {
// -----
/**
- * A label that can display 2 images depending on its internal state.
- * This acts as a button by firing the {@link SWT#Selection} listener.
- */
- private static class ToggleButton extends CLabel {
- private Image[] mImage = new Image[2];
- private boolean mMouseIn;
- private int mState = 0;
-
-
- public ToggleButton(Composite parent, int style, Image image1, Image image2) {
- super(parent, style);
- mImage[0] = image1;
- mImage[1] = image2;
- updateImage();
-
- addMouseListener(new MouseListener() {
- public void mouseDown(MouseEvent e) {
- // pass
- }
-
- public void mouseUp(MouseEvent e) {
- // We select on mouse-up, as it should be properly done since this is the
- // only way a user can cancel a button click by moving out of the button.
- if (mMouseIn && e.button == 1) {
- notifyListeners(SWT.Selection, new Event());
- }
- }
-
- public void mouseDoubleClick(MouseEvent e) {
- if (mMouseIn && e.button == 1) {
- notifyListeners(SWT.DefaultSelection, new Event());
- }
- }
- });
-
- addMouseTrackListener(new MouseTrackListener() {
- public void mouseExit(MouseEvent e) {
- if (mMouseIn) {
- mMouseIn = false;
- redraw();
- }
- }
-
- public void mouseEnter(MouseEvent e) {
- if (!mMouseIn) {
- mMouseIn = true;
- redraw();
- }
- }
-
- public void mouseHover(MouseEvent e) {
- // pass
- }
- });
- }
-
- @Override
- public int getStyle() {
- int style = super.getStyle();
- if (mMouseIn) {
- style |= SWT.SHADOW_IN;
- }
- return style;
- }
-
- /**
- * Sets current state.
- * @param state A value 0 or 1.
- */
- public void setState(int state) {
- assert state == 0 || state == 1;
- mState = state;
- updateImage();
- redraw();
- }
-
- /**
- * Returns the current state
- * @return Returns the current state, either 0 or 1.
- */
- public int getState() {
- return mState;
- }
-
- protected void updateImage() {
- setImage(mImage[getState()]);
- }
- }
-
- /**
- * A label that can display 2 images depending on its enabled/disabled state.
- * This acts as a button by firing the {@link SWT#Selection} listener.
- */
- private static class ImgDisabledButton extends ToggleButton {
- public ImgDisabledButton(Composite parent, int style,
- Image imageEnabled, Image imageDisabled) {
- super(parent, style, imageEnabled, imageDisabled);
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- updateImage();
- redraw();
- }
-
- @Override
- public void setState(int state) {
- throw new UnsupportedOperationException(); // not available for this type of button
- }
-
- @Override
- public int getState() {
- return (isDisposed() || !isEnabled()) ? 1 : 0;
- }
- }
-
- // -----
-
- /**
* Dialog used to display either the About page or the Settings (aka Options) page
* with a "close" button.
*/
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
index c5727e0..f8ec4ff 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
@@ -16,6 +16,7 @@
package com.android.sdkuilib.internal.tasks;
+import com.android.sdklib.ISdkLog;
import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskMonitor;
@@ -49,6 +50,8 @@ public final class ProgressView implements IProgressUiProvider {
/** The current mode of operation of the dialog. */
private State mState = State.IDLE;
+
+
// UI fields
private final Label mLabel;
private final Control mStopButton;
@@ -61,18 +64,31 @@ public final class ProgressView implements IProgressUiProvider {
*/
private final StringBuilder mLogText = new StringBuilder();
+ /** Logger object. Can be null. */
+ private final ISdkLog mLog;
+
+ private String mLastLogMsg = null;
/**
* Creates a new {@link ProgressView} object, a simple "holder" for the various
* widgets used to display and update a progress + status bar.
*
- * @param label The label of the current operation. Must not be null.
- * @param progressBar The progress bar showing the current progress. Must not be null.
- * @param stopButton The stop button. Optional. Can be null.
+ * @param label The label to display titles of status updates (e.g. task titles and
+ * calls to {@link #setDescription(String)}.) Must not be null.
+ * @param progressBar The progress bar to update during a task. Must not be null.
+ * @param stopButton The stop button. It will be disabled when there's no task that can
+ * be interrupted. A selection listener will be attached to it. Optional. Can be null.
+ * @param log An <em>optional</em> logger object that will be used to report all the log.
+ * If null, all logging will be collected here with a little UI to display it.
*/
- public ProgressView(Label label, ProgressBar progressBar, Control stopButton) {
+ public ProgressView(
+ Label label,
+ ProgressBar progressBar,
+ Control stopButton,
+ ISdkLog log) {
mLabel = label;
mProgressBar = progressBar;
+ mLog = log;
mProgressBar.setEnabled(false);
mStopButton = stopButton;
@@ -162,8 +178,15 @@ public final class ProgressView implements IProgressUiProvider {
mLabel.setText(description);
}
});
- synchronized (mLogText) {
- mLogText.append("** ").append(description);
+
+ if (acceptLog(description)) {
+ if (mLog != null) {
+ mLog.printf("%1$s", description);
+ } else {
+ synchronized (mLogText) {
+ mLogText.append(description);
+ }
+ }
}
}
@@ -172,8 +195,14 @@ public final class ProgressView implements IProgressUiProvider {
* This method can be invoked from a non-UI thread.
*/
public void log(String log) {
- synchronized (mLogText) {
- mLogText.append("=> ").append(log);
+ if (acceptLog(log)) {
+ if (mLog != null) {
+ mLog.printf(" %1$s", log);
+ } else {
+ synchronized (mLogText) {
+ mLogText.append(" ").append(log);
+ }
+ }
}
}
@@ -182,8 +211,14 @@ public final class ProgressView implements IProgressUiProvider {
* This method can be invoked from a non-UI thread.
*/
public void logError(String log) {
- synchronized (mLogText) {
- mLogText.append("=> ").append(log);
+ if (acceptLog(log)) {
+ if (mLog != null) {
+ mLog.error(null, " %1$s", log);
+ } else {
+ synchronized (mLogText) {
+ mLogText.append("ERROR: ").append(log);
+ }
+ }
}
}
@@ -193,8 +228,14 @@ public final class ProgressView implements IProgressUiProvider {
* This method can be invoked from a non-UI thread.
*/
public void logVerbose(String log) {
- synchronized (mLogText) {
- mLogText.append("=> ").append(log);
+ if (acceptLog(log)) {
+ if (mLog != null) {
+ mLog.printf(" %1$s", log);
+ } else {
+ synchronized (mLogText) {
+ mLogText.append(" ").append(log);
+ }
+ }
}
}
@@ -261,4 +302,32 @@ public final class ProgressView implements IProgressUiProvider {
return result[0];
}
+
+ // ----
+
+ /**
+ * Filter messages displayed in the log: <br/>
+ * - Messages with a % are typical part of a progress update and shouldn't be in the log. <br/>
+ * - Messages that are the same as the same output message should be output a second time.
+ *
+ * @param msg The potential log line to print.
+ * @return True if the log line should be printed, false otherwise.
+ */
+ private boolean acceptLog(String msg) {
+ if (msg == null) {
+ return false;
+ }
+
+ msg = msg.trim();
+ if (msg.indexOf('%') != -1) {
+ return false;
+ }
+
+ if (msg.equals(mLastLogMsg)) {
+ return false;
+ }
+
+ mLastLogMsg = msg;
+ return true;
+ }
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
index 56f2c7e..f2cd67d 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
@@ -28,8 +28,8 @@ import com.android.sdklib.internal.repository.ITaskMonitor;
import com.android.sdkuilib.internal.repository.SettingsController;
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
import com.android.sdkuilib.internal.tasks.ProgressTask;
-import com.android.sdkuilib.repository.IUpdaterWindow;
import com.android.sdkuilib.repository.UpdaterWindow;
+import com.android.sdkuilib.repository.UpdaterWindow.InvocationContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
@@ -1009,10 +1009,11 @@ public final class AvdSelector {
log = new MessageBoxLog("Result of SDK Manager", display, true /*logErrorsOnly*/);
}
- IUpdaterWindow window = new UpdaterWindow(
+ UpdaterWindow window = new UpdaterWindow(
mTable.getShell(),
log,
- mAvdManager.getSdkManager().getLocation());
+ mAvdManager.getSdkManager().getLocation(),
+ InvocationContext.AVD_SELECTOR);
window.open();
refresh(true /*reload*/); // UpdaterWindow uses its own AVD manager so this one must reload.
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
index 0fd0db2..a8c1570 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
@@ -17,6 +17,7 @@
package com.android.sdkuilib.repository;
import com.android.sdklib.ISdkLog;
+import com.android.sdkuilib.internal.repository.IUpdaterWindow;
import com.android.sdkuilib.internal.repository.UpdaterPage;
import com.android.sdkuilib.internal.repository.UpdaterWindowImpl;
import com.android.sdkuilib.internal.repository.UpdaterWindowImpl2;
@@ -27,26 +28,61 @@ import org.eclipse.swt.widgets.Shell;
/**
* Opens an SDK Updater Window.
*
- * This is the public interface for using the window.
+ * This is the public entry point for using the window.
*/
-public class UpdaterWindow implements IUpdaterWindow {
+public class UpdaterWindow {
+ /** The actual window implement to which this class delegates. */
private IUpdaterWindow mWindow;
/**
+ * Enum giving some indication of what is invoking this window.
+ * The behavior and UI will change slightly depending on the context.
+ * <p/>
+ * Note: if you add Android support to your specific IDE, you might want
+ * to specialize this context enum.
+ */
+ public enum InvocationContext {
+ /**
+ * The SDK Manager is invoked from the stand-alone 'android' tool.
+ * In this mode, we present an about box, a settings page.
+ * For SdkMan2, we also have a menu bar and link to the AVD manager.
+ */
+ STANDALONE,
+ /**
+ * The SDK Manager is invoked from an IDE.
+ * In this mode, we do not modify the menu bar. There is no about box
+ * and no settings (e.g. HTTP proxy settings are inherited from Eclipse.)
+ */
+ IDE,
+ /**
+ * The SDK Manager is invoked from the AVD Selector.
+ * For SdkMan1, this means the AVD page will be displayed first.
+ * For SdkMan2, we won't be using this.
+ */
+ AVD_SELECTOR
+ }
+
+ /**
* Creates a new window. Caller must call open(), which will block.
*
* @param parentShell Parent shell.
* @param sdkLog Logger. Cannot be null.
* @param osSdkRoot The OS path to the SDK root.
+ * @param context The {@link InvocationContext} to change the behavior depending on who's
+ * opening the SDK Manager.
*/
- public UpdaterWindow(Shell parentShell, ISdkLog sdkLog, String osSdkRoot) {
+ public UpdaterWindow(
+ Shell parentShell,
+ ISdkLog sdkLog,
+ String osSdkRoot,
+ InvocationContext context) {
// TODO right now the new PackagesPage is experimental and not enabled by default
if (System.getenv("ANDROID_SDKMAN_EXP") != null) { //$NON-NLS-1$
- mWindow = new UpdaterWindowImpl2(parentShell, sdkLog, osSdkRoot);
+ mWindow = new UpdaterWindowImpl2(parentShell, sdkLog, osSdkRoot, context);
} else {
- mWindow = new UpdaterWindowImpl(parentShell, sdkLog, osSdkRoot);
+ mWindow = new UpdaterWindowImpl(parentShell, sdkLog, osSdkRoot, context);
}
}
@@ -87,6 +123,7 @@ public class UpdaterWindow implements IUpdaterWindow {
/**
* Adds a new listener to be notified when a change is made to the content of the SDK.
+ * This should be called before {@link #open()}.
*/
public void addListener(ISdkChangeListener listener) {
mWindow.addListener(listener);