diff options
author | Tor Norbye <tnorbye@google.com> | 2012-06-14 11:37:43 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-06-14 14:43:11 -0700 |
commit | dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122 (patch) | |
tree | 7b4f2b347426120d5cbb8160529902aacc4a7c95 | |
parent | 7f10682cf646bcb3e761fbb6bcb2f645bd748c03 (diff) | |
download | sdk-dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122.zip sdk-dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122.tar.gz sdk-dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122.tar.bz2 |
Dependency support for the templates
Change-Id: Id6b0e5f65fc3a50b352423623332c47f7ab5085d
17 files changed, 514 insertions, 35 deletions
diff --git a/build/tools.atree b/build/tools.atree index afdeb75..abd2127 100644 --- a/build/tools.atree +++ b/build/tools.atree @@ -153,7 +153,7 @@ sdk/templates/projects/NewAndroidApplication tools/templates/p sdk/templates/activities/BlankActivity tools/templates/activities/BlankActivity sdk/templates/activities/MasterDetailFlow tools/templates/activities/MasterDetailFlow sdk/templates/other/CustomView tools/templates/other/CustomView -sdk/templates/resources tools/templates/resources +#sdk/templates/resources tools/templates/resources # SDK Controller sdk/apps/SdkController tools/apps/SdkController 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 7da3cc0..ebbd9f0 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 @@ -16,13 +16,16 @@ package com.android.ide.eclipse.adt.internal.actions; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog; import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.sdklib.NullSdkLog; import com.android.sdklib.SdkConstants; +import com.android.sdklib.SdkManager; import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.internal.project.ProjectProperties.PropertyType; import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy; @@ -62,6 +65,7 @@ import org.eclipse.ui.IWorkbenchWindowActionDelegate; import java.io.File; import java.io.IOException; import java.util.Iterator; +import java.util.Map; /** * An action to add the android-support-v4.jar compatibility library @@ -74,6 +78,12 @@ import java.util.Iterator; */ public class AddCompatibilityJarAction implements IObjectActionDelegate { + private static final String FD_ANDROID = "android"; //$NON-NLS-1$ + private static final String FD_SUPPORT = "support"; //$NON-NLS-1$ + private static final String FD_GRIDLAYOUT = "gridlayout"; //$NON-NLS-1$ + private static final String FD_V7 = "v7"; //$NON-NLS-1$ + private static final String FD_V4 = "v4"; //$NON-NLS-1$ + private static final String ANDROID_SUPPORT_V4_JAR = "android-support-v4.jar"; //$NON-NLS-1$ private ISelection mSelection; /** @@ -116,7 +126,7 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { * @return true if the installation was successful */ public static boolean install(final IProject project) { - File jarPath = installSupport(); + File jarPath = installSupport(-1); if (jarPath != null) { try { return copyJarIntoProject(project, jarPath) != null; @@ -128,7 +138,21 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { return false; } - private static File installSupport() { + /** + * Installs the Android Support library into the SDK extras/ folder. If a minimum + * revision number is specified, this method will check whether the package is already + * installed, and if the installed revision is at least as high as the requested revision, + * this method will exit without performing an update. + * + * @param minimumRevision a minimum revision, or -1 to upgrade + * unconditionally. Note that this does <b>NOT</b> specify which + * revision to install; the latest version will always be + * installed. + * @return the location of the support jar file, or null if something went + * wrong + */ + @Nullable + public static File installSupport(int minimumRevision) { final Sdk sdk = Sdk.getCurrent(); if (sdk == null) { @@ -138,6 +162,18 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { return null; } + String sdkLocation = sdk.getSdkLocation(); + if (minimumRevision > 0) { + File path = getCompatJarFile(); + if (path != null) { + assert path.exists(); // guaranteed by the getCompatJarFile call + int installedRevision = getInstalledRevision(); + if (installedRevision != -1 && minimumRevision >= installedRevision) { + return path; + } + } + } + // TODO: For the generic action, check the library isn't in the project already. // First call the package manager to make sure the package is installed @@ -146,10 +182,10 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { AdtUpdateDialog window = new AdtUpdateDialog( AdtPlugin.getDisplay().getActiveShell(), new AdtConsoleSdkLog(), - sdk.getSdkLocation()); + sdkLocation); Pair<Boolean, File> result = window.installExtraPackage( - "android", "support"); //$NON-NLS-1$ //$NON-NLS-2$ + FD_ANDROID, FD_SUPPORT); // TODO: Make sure the version is at the required level; we know we need at least one // containing the v7 support @@ -163,8 +199,8 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { // vN/android-support-vN.jar. Eventually we'll want to rely on info from the // package manifest anyway so this is irrelevant. - File path = new File(result.getSecond(), "v4"); //$NON-NLS-1$ - final File jarPath = new File(path, "android-support-v4.jar"); //$NON-NLS-1$ + File path = new File(result.getSecond(), FD_V4); + final File jarPath = new File(path, ANDROID_SUPPORT_V4_JAR); if (!jarPath.isFile()) { AdtPlugin.printErrorToConsole("Android Compatibility JAR not found:", @@ -176,6 +212,27 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { } /** + * Returns the installed revision number of the Android Compatibility + * library, or -1 if the package is not installed. + * + * @return the installed revision number, or -1 + */ + public static int getInstalledRevision() { + final Sdk sdk = Sdk.getCurrent(); + if (sdk != null) { + String sdkLocation = sdk.getSdkLocation(); + SdkManager manager = SdkManager.createManager(sdkLocation, new NullSdkLog()); + Map<String, Integer> versions = manager.getExtrasVersions(); + Integer version = versions.get("android/support"); //$NON-NLS-1$ + if (version != null) { + return version.intValue(); + } + } + + return -1; + } + + /** * Similar to {@link #install}, but rather than copy a jar into the given * project, it creates a new library project in the workspace for the * compatibility library, and adds a library dependency on the newly @@ -188,29 +245,23 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { * likely to be successful - e.g. the user has at least agreed to * all installation prompts.) */ - public static boolean installLibrary(final IProject project, boolean waitForFinish) { + public static boolean installGridLayoutLibrary(final IProject project, boolean waitForFinish) { final IJavaProject javaProject = JavaCore.create(project); if (javaProject != null) { - File sdk = new File(Sdk.getCurrent().getSdkLocation()); - File supportPath = new File(sdk, - SdkConstants.FD_EXTRAS + File.separator - + "android" + File.separator //$NON-NLS-1$ - + "support"); //$NON-NLS-1$ + File supportPath = getCompatPackageDir(); if (!supportPath.isDirectory()) { - File path = installSupport(); + File path = installSupport(8); // GridLayout arrived in rev 7 and fixed in rev 8 if (path == null) { return false; } assert path.equals(supportPath); } - File libraryPath = new File(supportPath, - "v7" + File.separator //$NON-NLS-1$ - + "gridlayout"); //$NON-NLS-1$ + File libraryPath = new File(supportPath, FD_V7 + File.separator + FD_GRIDLAYOUT); if (!libraryPath.isDirectory()) { // Upgrade support package: it's out of date. The SDK manager will // perform an upgrade to the latest version if the package is already installed. - File path = installSupport(); + File path = installSupport(-1); if (path == null) { return false; } @@ -228,6 +279,36 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate { } /** + * Returns the directory containing the support libraries (v4, v7, v13, + * ...), which may or may not exist + */ + private static File getCompatPackageDir() { + File sdk = new File(Sdk.getCurrent().getSdkLocation()); + File supportPath = new File(sdk, + SdkConstants.FD_EXTRAS + File.separator + + FD_ANDROID + File.separator + + FD_SUPPORT); + return supportPath; + } + + /** + * Returns a path to the installed jar file for the compatibility library, + * or null if it does not exist + * + * @return a path to the library or null + */ + @Nullable + public static File getCompatJarFile() { + File supportDir = getCompatPackageDir(); + File path = new File(supportDir, FD_V4 + File.separator + ANDROID_SUPPORT_V4_JAR); + if (path.exists()) { + return path; + } + + return null; + } + + /** * Creates a library project in the Eclipse workspace out of the grid layout project * in the SDK tree. * diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java index 45590b7..d5f5c3c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java @@ -121,7 +121,7 @@ public class CompatibilityLibraryHelper { } } else { // Install library AND add dependency - if (!AddCompatibilityJarAction.installLibrary( + if (!AddCompatibilityJarAction.installGridLayoutLibrary( project, true /* waitForFinish */)) { return tag; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizard.java index 5115385..8f5a3e1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizard.java @@ -173,6 +173,12 @@ public class WelcomeWizard extends Wizard { // are required dependencies of any platform. boolean result = updater.installNewSdk(apiLevels); + // TODO: Install extra package here as well since it is now core to most of + // the templates + // if (result) { + // updater.installExtraPackage(vendor, path); + // } + if (disposeShell) { shell.dispose(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java new file mode 100644 index 0000000..bdd53b8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.wizards.templates; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction; +import com.android.util.Pair; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.browser.IWebBrowser; + +import java.io.File; +import java.net.URL; +import java.util.List; + +class InstallDependencyPage extends WizardPage implements SelectionListener { + /** + * The compatibility library. This is the only library the templates + * currently support. The appearance of any other dependency in this + * template will be flagged as a validation error (and the user encouraged + * to upgrade to a newer ADT + */ + static final String SUPPORT_LIBRARY_NAME = "android-support-v4"; //$NON-NLS-1$ + + /** URL containing more info */ + private static final String URL = + "http://developer.android.com/sdk/compatibility-library.html"; //$NON-NLS-1$ + + private Button mCheckButton; + private Button mInstallButton; + private Link mLink; + private TemplateMetadata mTemplate; + + InstallDependencyPage() { + super("dependency"); //$NON-NLS-1$ + setTitle("Install Dependencies"); + } + + void setTemplate(TemplateMetadata template) { + if (template != mTemplate) { + mTemplate = template; + if (getControl() != null) { + validatePage(); + } + } + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + updateVersionLabels(); + validatePage(); + } + } + + @Override + public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NULL); + setControl(container); + container.setLayout(new GridLayout(2, false)); + // Remaining contents are created lazily, since this page is always added to + // the page list, but typically not shown + + Label dependLabel = new Label(container, SWT.WRAP); + GridData gd_dependLabel = new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1); + gd_dependLabel.widthHint = NewTemplatePage.WIZARD_PAGE_WIDTH - 50; + dependLabel.setLayoutData(gd_dependLabel); + dependLabel.setText("This template depends on the Android Support library, which is " + + "either not installed, or the template depends on a more recent version than " + + "the one you have installed."); + + mLink = new Link(container, SWT.NONE); + mLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1)); + mLink.setText("<a href=\"" + URL + "\">" + URL + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + mLink.addSelectionListener(this); + + Label lblNewLabel_1 = new Label(container, SWT.NONE); + lblNewLabel_1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + + requiredLabel = new Label(container, SWT.NONE); + requiredLabel.setText("Required version:"); + + mRequiredVersion = new Label(container, SWT.NONE); + mRequiredVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + + installedLabel = new Label(container, SWT.NONE); + installedLabel.setText("Installed version:"); + + mInstalledVersion = new Label(container, SWT.NONE); + mInstalledVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + + Label lblNewLabel = new Label(container, SWT.NONE); + lblNewLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + + Label descLabel = new Label(container, SWT.WRAP); + GridData gd_descLabel = new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1); + gd_descLabel.widthHint = 550; + descLabel.setLayoutData(gd_descLabel); + descLabel.setText( + "You can install or upgrade it by clicking the Install button below, or " + + "alternatively, you can install it outside of Eclipse with the SDK Manager, " + + "then click on \"Check Again\" to proceed."); + + mInstallButton = new Button(container, SWT.NONE); + mInstallButton.setText("Install/Upgrade"); + mInstallButton.addSelectionListener(this); + + mCheckButton = new Button(container, SWT.NONE); + mCheckButton.setText("Check Again"); + mCheckButton.addSelectionListener(this); + + mInstallButton.setFocus(); + } + + private void showNextPage() { + validatePage(); + if (isPageComplete()) { + // Finish button will be enabled now + mInstallButton.setEnabled(false); + mCheckButton.setEnabled(false); + + IWizard wizard = getWizard(); + IWizardPage next = wizard.getNextPage(this); + if (next != null) { + wizard.getContainer().showPage(next); + } + } + } + + @Override + public boolean isPageComplete() { + if (mTemplate == null) { + return true; + } + + return super.isPageComplete() && isInstalled(); + } + + private boolean isInstalled() { + return isInstalled(mTemplate.getDependencies()); + } + + static String sCachedName; + static int sCachedVersion; + private Label requiredLabel; + private Label installedLabel; + private Label mRequiredVersion; + private Label mInstalledVersion; + + public static boolean isInstalled(List<Pair<String, Integer>> dependencies) { + for (Pair<String, Integer> dependency : dependencies) { + String name = dependency.getFirst(); + int required = dependency.getSecond(); + + int installed = -1; + if (SUPPORT_LIBRARY_NAME.equals(name)) { + installed = getInstalledSupportLibVersion(); + } + + if (installed == -1) { + return false; + } + if (required > installed) { + return false; + } + } + + return true; + } + + private static int getInstalledSupportLibVersion() { + if (SUPPORT_LIBRARY_NAME.equals(sCachedName)) { + return sCachedVersion; + } else { + int version = AddCompatibilityJarAction.getInstalledRevision(); + sCachedName = SUPPORT_LIBRARY_NAME; + sCachedVersion = version; + return version; + } + } + + private void updateVersionLabels() { + int version = getInstalledSupportLibVersion(); + if (version == -1) { + mInstalledVersion.setText("Not installed"); + } else { + mInstalledVersion.setText(Integer.toString(version)); + } + + if (mTemplate != null) { + for (Pair<String, Integer> dependency : mTemplate.getDependencies()) { + String name = dependency.getFirst(); + if (name.equals(SUPPORT_LIBRARY_NAME)) { + int required = dependency.getSecond(); + mRequiredVersion.setText(Integer.toString(required)); + break; + } + } + } + } + + private void validatePage() { + if (mTemplate == null) { + return; + } + + IStatus status = null; + + List<Pair<String, Integer>> dependencies = mTemplate.getDependencies(); + if (dependencies.size() > 1 || dependencies.size() == 1 + && !dependencies.get(0).getFirst().equals(SUPPORT_LIBRARY_NAME)) { + status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, + "Unsupported template dependency: Upgrade your Android Eclipse plugin"); + } + + setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); + if (status != null) { + setMessage(status.getMessage(), + status.getSeverity() == IStatus.ERROR + ? IMessageProvider.ERROR : IMessageProvider.WARNING); + } else { + setErrorMessage(null); + setMessage(null); + } + } + + // ---- Implements SelectionListener ---- + + @Override + public void widgetSelected(SelectionEvent e) { + Object source = e.getSource(); + if (source == mCheckButton) { + sCachedName = null; + if (isInstalled()) { + showNextPage(); + } else { + updateVersionLabels(); + } + } else if (source == mInstallButton) { + sCachedName = null; + for (Pair<String, Integer> dependency : mTemplate.getDependencies()) { + String name = dependency.getFirst(); + if (SUPPORT_LIBRARY_NAME.equals(name)) { + int version = dependency.getSecond(); + File installed = AddCompatibilityJarAction.installSupport(version); + if (installed != null) { + showNextPage(); + } else { + updateVersionLabels(); + } + } + } + } else if (source == mLink) { + try { + IWorkbench workbench = PlatformUI.getWorkbench(); + IWebBrowser browser = workbench.getBrowserSupport().getExternalBrowser(); + browser.openURL(new URL(URL)); + } catch (Exception ex) { + String message = String.format("Could not open browser. Vist\n%1$s\ninstead.", + URL); + MessageDialog.openError(getShell(), "Browser Error", message); + } + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java index a2e3518..52d7cec 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java @@ -54,10 +54,10 @@ public class NewActivityWizard extends Wizard implements INewWizard { private IWorkbench mWorkbench; private UpdateToolsPage mUpdatePage; - private NewProjectPage mMainPage; private NewTemplatePage mTemplatePage; private ActivityPage mActivityPage; private NewProjectWizardState mValues; + protected InstallDependencyPage mDependencyPage; private NewTemplateWizardState mActivityValues; /** Creates a new {@link NewActivityWizard} */ @@ -99,7 +99,7 @@ public class NewActivityWizard extends Wizard implements INewWizard { @Override public IWizardPage getStartingPage() { if (mUpdatePage != null && mUpdatePage.isPageComplete()) { - return mMainPage; + return mActivityPage; } return super.getStartingPage(); } @@ -118,6 +118,20 @@ public class NewActivityWizard extends Wizard implements INewWizard { addPage(mTemplatePage); } return mTemplatePage; + } else if (page == mTemplatePage) { + TemplateMetadata template = mActivityValues.getTemplateHandler().getTemplate(); + if (template != null) { + if (InstallDependencyPage.isInstalled(template.getDependencies())) { + return null; + } else { + if (mDependencyPage == null) { + mDependencyPage = new InstallDependencyPage(); + addPage(mDependencyPage); + } + mDependencyPage.setTemplate(template); + return mDependencyPage; + } + } } return super.getNextPage(page); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java index 1de4b2c..2d67086 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java @@ -78,6 +78,7 @@ public class NewProjectWizard extends Wizard implements INewWizard { private AppSkeletonPage mAppSkeletonPage; private NewTemplatePage mTemplatePage; private ActivityPage mActivityPage; + protected InstallDependencyPage mDependencyPage; private ConfigureAssetSetPage mIconPage; private NewProjectWizardState mValues; @@ -154,7 +155,21 @@ public class NewProjectWizard extends Wizard implements INewWizard { return mTemplatePage; } - if (page == mTemplatePage || !mValues.createActivity && page == mActivityPage) { + if (page == mTemplatePage ) { + TemplateMetadata template = mValues.activityValues.getTemplateHandler().getTemplate(); + if (template != null + && !InstallDependencyPage.isInstalled(template.getDependencies())) { + if (mDependencyPage == null) { + mDependencyPage = new InstallDependencyPage(); + addPage(mDependencyPage); + } + mDependencyPage.setTemplate(template); + return mDependencyPage; + } + } + + if (page == mTemplatePage || !mValues.createActivity && page == mActivityPage + || page == mDependencyPage) { if (mValues.createIcon) { if (mIconPage == null) { // Bundle asset studio wizard to create the launcher icon diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java index 1e443bc..ea9774e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java @@ -461,7 +461,7 @@ public class NewTemplatePage extends WizardPage @Override public boolean isPageComplete() { // Force user to reach this page before hitting Finish - return mShown; + return mShown && super.isPageComplete(); } @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java index 28f5ca6..666e2f6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java @@ -59,6 +59,7 @@ public class NewTemplateWizard extends Wizard implements INewWizard { protected IWorkbench mWorkbench; protected NewTemplatePage mMainPage; protected UpdateToolsPage mUpdatePage; + protected InstallDependencyPage mDependencyPage; protected NewTemplateWizardState mValues; private final String mTemplateName; @@ -115,6 +116,22 @@ public class NewTemplateWizard extends Wizard implements INewWizard { @Override public IWizardPage getNextPage(IWizardPage page) { + if (page == mMainPage) { + TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); + if (template != null) { + if (InstallDependencyPage.isInstalled(template.getDependencies())) { + return null; + } else { + if (mDependencyPage == null) { + mDependencyPage = new InstallDependencyPage(); + addPage(mDependencyPage); + } + mDependencyPage.setTemplate(template); + return mDependencyPage; + } + } + } + return super.getNextPage(page); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java index 1532228..16b38e3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java @@ -17,7 +17,9 @@ package com.android.ide.eclipse.adt.internal.wizards.templates; import static com.android.ide.eclipse.adt.AdtConstants.DOT_FTL; import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML; +import static com.android.ide.eclipse.adt.internal.wizards.templates.InstallDependencyPage.SUPPORT_LIBRARY_NAME; import static com.android.sdklib.SdkConstants.FD_EXTRAS; +import static com.android.sdklib.SdkConstants.FD_NATIVE_LIBS; import static com.android.sdklib.SdkConstants.FD_TEMPLATES; import static com.android.sdklib.SdkConstants.FD_TOOLS; @@ -25,6 +27,7 @@ import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; +import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatPreferences; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlPrettyPrinter; @@ -35,6 +38,7 @@ import com.android.manifmerger.MergerLog; import com.android.resources.ResourceFolderType; import com.android.sdklib.SdkConstants; import com.google.common.base.Charsets; +import com.google.common.collect.Lists; import com.google.common.io.Files; import freemarker.cache.TemplateLoader; @@ -75,8 +79,6 @@ import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import lombok.ast.libs.org.parboiled.google.collect.Lists; - /** * Handler which manages instantiating FreeMarker templates, copying resources * and merging into existing files @@ -435,9 +437,25 @@ class TemplateHandler { if (path != null) { execute(freemarker, path, paramMap, outputPath); } + } else if (TAG_DEPENDENCY.equals(name)) { + String dependencyName = attributes.getValue(ATTR_NAME); + if (dependencyName.equals(SUPPORT_LIBRARY_NAME)) { + // We assume the revision requirement has been satisfied + // by the wizard + File path = AddCompatibilityJarAction.getCompatJarFile(); + if (path != null) { + File to = new File(outputPath, FD_NATIVE_LIBS + + File.separator + path.getName()); + try { + copy(path, to); + } catch (IOException ioe) { + AdtPlugin.log(ioe, null); + } + } + } } else if (!name.equals("template") && !name.equals("category") && !name.equals("option") && !name.equals(TAG_THUMBS) && - !name.equals(TAG_THUMB)) { + !name.equals(TAG_THUMB) && !name.equals(TAG_DEPENDENCY)) { System.err.println("WARNING: Unknown template directive " + name); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java index db0f8ce..f7037f1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java @@ -24,6 +24,7 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHan import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.util.Pair; import org.w3c.dom.Attr; import org.w3c.dom.Document; @@ -33,15 +34,19 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.ast.libs.org.parboiled.google.collect.Lists; + /** An ADT template along with metadata */ class TemplateMetadata { private final Document mDocument; private final List<Parameter> mParameters; private final Map<String, Parameter> mParameterMap; + private List<Pair<String, Integer>> mDependencies; TemplateMetadata(@NonNull Document document) { mDocument = document; @@ -59,7 +64,7 @@ class TemplateMetadata { } } - public boolean isSupported() { + boolean isSupported() { String versionString = mDocument.getDocumentElement().getAttribute(ATTR_FORMAT); if (versionString != null && !versionString.isEmpty()) { try { @@ -153,6 +158,34 @@ class TemplateMetadata { return null; } + /** + * Returns the dependencies (as a list of pairs of names and revisions) + * required by this template + */ + List<Pair<String, Integer>> getDependencies() { + if (mDependencies == null) { + NodeList elements = mDocument.getElementsByTagName(TemplateHandler.TAG_DEPENDENCY); + if (elements.getLength() == 0) { + return Collections.emptyList(); + } + + List<Pair<String, Integer>> dependencies = Lists.newArrayList(); + for (int i = 0, n = elements.getLength(); i < n; i++) { + Element element = (Element) elements.item(i); + String name = element.getAttribute(TemplateHandler.ATTR_NAME); + int revision = -1; + String revisionString = element.getAttribute(TemplateHandler.ATTR_REVISION); + if (!revisionString.isEmpty()) { + revision = Integer.parseInt(revisionString); + } + dependencies.add(Pair.of(name, revision)); + } + mDependencies = dependencies; + } + + return mDependencies; + } + /** Returns the list of available parameters */ @NonNull List<Parameter> getParameters() { diff --git a/templates/activities/BlankActivity/recipe.xml.ftl b/templates/activities/BlankActivity/recipe.xml.ftl index 97b9ba7..a6d0ce9 100644 --- a/templates/activities/BlankActivity/recipe.xml.ftl +++ b/templates/activities/BlankActivity/recipe.xml.ftl @@ -13,11 +13,6 @@ <merge from="res/values-large/dimens.xml" /> <merge from="res/values/strings.xml.ftl" /> - <!-- Always include the support library because we use NavUtils, ViewPager, etc. --> - <!-- TODO: automatically overwrite only if the version is newer, otherwise silently fail --> - <copy from="${android.templatesRes}/android-support-v4.jar.bin" - to="libs/android-support-v4.jar" /> - <!-- Decide what kind of layout to add (viewpager or not) --> <#if navType?contains("pager")> <instantiate from="res/layout/activity_pager.xml.ftl" diff --git a/templates/activities/BlankActivity/template.xml b/templates/activities/BlankActivity/template.xml index 997051e..bce675d 100644 --- a/templates/activities/BlankActivity/template.xml +++ b/templates/activities/BlankActivity/template.xml @@ -4,6 +4,7 @@ revision="1" name="New Blank Activity" description="Creates a new blank activity, with optional inner navigation."> + <dependency name="android-support-v4" revision="8" /> <category value="Activities" /> diff --git a/templates/activities/MasterDetailFlow/recipe.xml.ftl b/templates/activities/MasterDetailFlow/recipe.xml.ftl index a07635e..2c1f057 100644 --- a/templates/activities/MasterDetailFlow/recipe.xml.ftl +++ b/templates/activities/MasterDetailFlow/recipe.xml.ftl @@ -2,9 +2,6 @@ <recipe> <merge from="AndroidManifest.xml.ftl" /> - <copy from="${android.templatesRes}/android-support-v4.jar.bin" - to="libs/android-support-v4.jar" /> - <merge from="res/values-large/refs.xml.ftl" /> <merge from="res/values-sw600dp/refs.xml.ftl" /> <merge from="res/values/strings.xml.ftl" /> diff --git a/templates/activities/MasterDetailFlow/template.xml b/templates/activities/MasterDetailFlow/template.xml index 4f759cf..05ddb68 100644 --- a/templates/activities/MasterDetailFlow/template.xml +++ b/templates/activities/MasterDetailFlow/template.xml @@ -4,6 +4,7 @@ revision="1" name="New Master/Detail Flow" description="Creates a new master/detail flow, which is two columns on tablets, and one column on smaller screens. This creates a master fragment, detail fragment, and two activities."> + <dependency name="android-support-v4" revision="8" /> <thumbs> <thumb>template_master_detail.png</thumb> diff --git a/templates/projects/NewAndroidApplication/template.xml b/templates/projects/NewAndroidApplication/template.xml index f0ee375..c8464c5 100644 --- a/templates/projects/NewAndroidApplication/template.xml +++ b/templates/projects/NewAndroidApplication/template.xml @@ -4,6 +4,7 @@ revision="1" name="New Android Application" description="Creates a new Android application with an activity."> + <dependency name="android-support-v4" revision="8" /> <thumbs> <thumb>template_new_project.png</thumb> diff --git a/templates/resources/android-support-v4.jar.bin b/templates/resources/android-support-v4.jar.bin Binary files differdeleted file mode 100644 index d006198..0000000 --- a/templates/resources/android-support-v4.jar.bin +++ /dev/null |