diff options
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);
|