diff --git a/build/sdk.atree b/build/sdk.atree index 20542a26f..174991507 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -58,6 +58,9 @@ development/tools/scripts/strings.template platforms/${PLATFORM_NAME}/templates/ development/tools/scripts/android_rules.xml platforms/${PLATFORM_NAME}/templates/android_rules.xml development/tools/scripts/android_test_rules.xml platforms/${PLATFORM_NAME}/templates/android_test_rules.xml development/tools/scripts/build.template tools/lib/build.template +development/tools/scripts/icon_ldpi.png platforms/${PLATFORM_NAME}/templates/icon_ldpi.png +development/tools/scripts/icon_mdpi.png platforms/${PLATFORM_NAME}/templates/icon_mdpi.png +development/tools/scripts/icon_hdpi.png platforms/${PLATFORM_NAME}/templates/icon_hdpi.png # emacs support development/tools/scripts/android.el tools/lib/android.el diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java index d8989c2f0..df333a503 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java @@ -20,6 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidConstants; import com.android.ide.eclipse.adt.internal.project.AndroidNature; import com.android.ide.eclipse.adt.internal.project.ProjectHelper; +import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreationPage.IMainInfo; import com.android.ide.eclipse.adt.internal.wizards.newproject.NewTestProjectCreationPage.TestInfo; @@ -132,6 +133,12 @@ public class NewProjectWizard extends Wizard implements INewWizard { SdkConstants.FD_ASSETS + AndroidConstants.WS_SEP; private static final String DRAWABLE_DIRECTORY = SdkConstants.FD_DRAWABLE + AndroidConstants.WS_SEP; + private static final String DRAWABLE_HDPI_DIRECTORY = + SdkConstants.FD_DRAWABLE + "-" + Density.HIGH.getValue() + AndroidConstants.WS_SEP; //$NON-NLS-1$ + private static final String DRAWABLE_MDPI_DIRECTORY = + SdkConstants.FD_DRAWABLE + "-" + Density.MEDIUM.getValue() + AndroidConstants.WS_SEP; //$NON-NLS-1$ + private static final String DRAWABLE_LDPI_DIRECTORY = + SdkConstants.FD_DRAWABLE + "-" + Density.LOW.getValue() + AndroidConstants.WS_SEP; //$NON-NLS-1$ private static final String LAYOUT_DIRECTORY = SdkConstants.FD_LAYOUT + AndroidConstants.WS_SEP; private static final String VALUES_DIRECTORY = @@ -159,7 +166,10 @@ public class NewProjectWizard extends Wizard implements INewWizard { + "strings.template"; //$NON-NLS-1$ private static final String TEMPLATE_STRING = TEMPLATES_DIRECTORY + "string.template"; //$NON-NLS-1$ - private static final String ICON = "icon.png"; //$NON-NLS-1$ + private static final String PROJECT_ICON = "icon.png"; //$NON-NLS-1$ + private static final String ICON_HDPI = "icon_hdpi.png"; //$NON-NLS-1$ + private static final String ICON_MDPI = "icon_mdpi.png"; //$NON-NLS-1$ + private static final String ICON_LDPI = "icon_ldpi.png"; //$NON-NLS-1$ private static final String STRINGS_FILE = "strings.xml"; //$NON-NLS-1$ @@ -170,7 +180,10 @@ public class NewProjectWizard extends Wizard implements INewWizard { private static final String[] DEFAULT_DIRECTORIES = new String[] { BIN_DIRECTORY, RES_DIRECTORY, ASSETS_DIRECTORY }; private static final String[] RES_DIRECTORIES = new String[] { - DRAWABLE_DIRECTORY, LAYOUT_DIRECTORY, VALUES_DIRECTORY}; + DRAWABLE_DIRECTORY, LAYOUT_DIRECTORY, VALUES_DIRECTORY }; + private static final String[] RES_DENSITY_ENABLED_DIRECTORIES = new String[] { + DRAWABLE_HDPI_DIRECTORY, DRAWABLE_MDPI_DIRECTORY, DRAWABLE_LDPI_DIRECTORY, + LAYOUT_DIRECTORY, VALUES_DIRECTORY }; private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$ private static final String JAVA_ACTIVITY_TEMPLATE = "java_file.template"; //$NON-NLS-1$ @@ -587,6 +600,10 @@ public class NewProjectWizard extends Wizard implements INewWizard { Map dictionary) throws CoreException, IOException { + // get the project target + IAndroidTarget target = (IAndroidTarget) parameters.get(PARAM_SDK_TARGET); + boolean legacy = target.getVersion().getApiLevel() < 4; + // Create project and open it project.create(description, new SubProgressMonitor(monitor, 10)); if (monitor.isCanceled()) throw new OperationCanceledException(); @@ -605,7 +622,11 @@ public class NewProjectWizard extends Wizard implements INewWizard { addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolders, monitor); // Create the resource folders in the project if they don't already exist. - addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor); + if (legacy) { + addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor); + } else { + addDefaultDirectories(project, RES_DIRECTORY, RES_DENSITY_ENABLED_DIRECTORIES, monitor); + } // Setup class path: mark folders as source folders IJavaProject javaProject = JavaCore.create(project); @@ -624,7 +645,7 @@ public class NewProjectWizard extends Wizard implements INewWizard { addManifest(project, parameters, dictionary, monitor); // add the default app icon - addIcon(project, monitor); + addIcon(project, legacy, monitor); // Create the default package components addSampleCode(project, sourceFolders[0], parameters, dictionary, monitor); @@ -650,7 +671,8 @@ public class NewProjectWizard extends Wizard implements INewWizard { // the currently-empty current list. desc.setReferencedProjects(new IProject[] { refProject }); - project.setDescription(desc, IResource.KEEP_HISTORY, new SubProgressMonitor(monitor, 10)); + project.setDescription(desc, IResource.KEEP_HISTORY, + new SubProgressMonitor(monitor, 10)); IClasspathEntry entry = JavaCore.newProjectEntry( refProject.getFullPath(), //path @@ -664,8 +686,7 @@ public class NewProjectWizard extends Wizard implements INewWizard { } } - Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET), - null /* apkConfigMap*/); + Sdk.getCurrent().setProject(project, target, null /* apkConfigMap*/); // Fix the project to make sure all properties are as expected. // Necessary for existing projects and good for new ones to. @@ -839,23 +860,58 @@ public class NewProjectWizard extends Wizard implements INewWizard { * Adds default application icon to the project. * * @param project The Java Project to update. + * @param legacy whether we're running in legacy mode (no density support) * @param monitor An existing monitor. * @throws CoreException if the method fails to update the project. */ - private void addIcon(IProject project, IProgressMonitor monitor) + private void addIcon(IProject project, boolean legacy, IProgressMonitor monitor) throws CoreException { - IFile file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP - + DRAWABLE_DIRECTORY + AndroidConstants.WS_SEP + ICON); - if (!file.exists()) { - // read the content from the template - byte[] buffer = AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON); - - // if valid - if (buffer != null) { - // Save in the project - InputStream stream = new ByteArrayInputStream(buffer); - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); + if (legacy) { // density support + // do medium density icon only, in the default drawable folder. + IFile file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP + + DRAWABLE_DIRECTORY + AndroidConstants.WS_SEP + PROJECT_ICON); + if (!file.exists()) { + addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_MDPI), monitor); } + } else { + // do all 3 icons. + IFile file; + + // high density + file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP + + DRAWABLE_HDPI_DIRECTORY + AndroidConstants.WS_SEP + PROJECT_ICON); + if (!file.exists()) { + addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_HDPI), monitor); + } + + // medium density + file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP + + DRAWABLE_MDPI_DIRECTORY + AndroidConstants.WS_SEP + PROJECT_ICON); + if (!file.exists()) { + addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_MDPI), monitor); + } + + // low density + file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP + + DRAWABLE_LDPI_DIRECTORY + AndroidConstants.WS_SEP + PROJECT_ICON); + if (!file.exists()) { + addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_LDPI), monitor); + } + } + } + + /** + * Creates a file from a data source. + * @param dest the file to write + * @param source the content of the file. + * @param monitor the progress monitor + * @throws CoreException + */ + private void addFile(IFile dest, byte[] source, IProgressMonitor monitor) throws CoreException { + if (source != null) { + // Save in the project + InputStream stream = new ByteArrayInputStream(source); + dest.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon.png b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon.png deleted file mode 100644 index 75024841d..000000000 Binary files a/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon.png and /dev/null differ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_hdpi.png b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_hdpi.png new file mode 100644 index 000000000..8074c4c57 Binary files /dev/null and b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_hdpi.png differ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_ldpi.png b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_ldpi.png new file mode 100644 index 000000000..1095584ec Binary files /dev/null and b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_ldpi.png differ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_mdpi.png b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_mdpi.png new file mode 100644 index 000000000..a07c69fa5 Binary files /dev/null and b/tools/eclipse/plugins/com.android.ide.eclipse.adt/templates/icon_mdpi.png differ diff --git a/tools/scripts/AndroidManifest.template b/tools/scripts/AndroidManifest.template index 9b07072f5..f14f1475c 100644 --- a/tools/scripts/AndroidManifest.template +++ b/tools/scripts/AndroidManifest.template @@ -3,7 +3,7 @@ package="PACKAGE" android:versionCode="1" android:versionName="1.0"> - + diff --git a/tools/scripts/icon_hdpi.png b/tools/scripts/icon_hdpi.png new file mode 100644 index 000000000..8074c4c57 Binary files /dev/null and b/tools/scripts/icon_hdpi.png differ diff --git a/tools/scripts/icon_ldpi.png b/tools/scripts/icon_ldpi.png new file mode 100644 index 000000000..1095584ec Binary files /dev/null and b/tools/scripts/icon_ldpi.png differ diff --git a/tools/scripts/icon_mdpi.png b/tools/scripts/icon_mdpi.png new file mode 100644 index 000000000..a07c69fa5 Binary files /dev/null and b/tools/scripts/icon_mdpi.png differ diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java index 639479584..e9e599967 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java @@ -29,6 +29,9 @@ import org.xml.sax.InputSource; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; @@ -66,6 +69,8 @@ public class ProjectCreator { private final static String PH_ACTIVITY_TESTED_CLASS_NAME = "ACTIVITY_TESTED_CLASS_NAME"; /** Project name substitution string used in template files, i.e. "PROJECT_NAME". */ private final static String PH_PROJECT_NAME = "PROJECT_NAME"; + /** Application icon substitution string used in the manifest template */ + private final static String PH_ICON = "ICON"; /** Pattern for characters accepted in a project name. Since this will be used as a * directory name, we're being a bit conservative on purpose: dot and space cannot be used. */ @@ -106,6 +111,7 @@ public class ProjectCreator { /** default UID. This will not be serialized anyway. */ private static final long serialVersionUID = 1L; + @SuppressWarnings("unused") ProjectCreateException(String message) { super(message); } @@ -329,19 +335,26 @@ public class ProjectCreator { } // create other useful folders - File resourceFodler = createDirs(projectFolder, SdkConstants.FD_RESOURCES); + File resourceFolder = createDirs(projectFolder, SdkConstants.FD_RESOURCES); createDirs(projectFolder, SdkConstants.FD_OUTPUT); createDirs(projectFolder, SdkConstants.FD_NATIVE_LIBS); if (isTestProject == false) { /* Make res files only for non test projects */ - File valueFolder = createDirs(resourceFodler, SdkConstants.FD_VALUES); + File valueFolder = createDirs(resourceFolder, SdkConstants.FD_VALUES); installTemplate("strings.template", new File(valueFolder, "strings.xml"), keywords, target); - File layoutFolder = createDirs(resourceFodler, SdkConstants.FD_LAYOUT); + File layoutFolder = createDirs(resourceFolder, SdkConstants.FD_LAYOUT); installTemplate("layout.template", new File(layoutFolder, "main.xml"), keywords, target); + + // create the icons + if (installIcons(resourceFolder, target)) { + keywords.put(PH_ICON, "android:icon=\"@drawable/icon\""); + } else { + keywords.put(PH_ICON, ""); + } } /* Make AndroidManifest.xml and build.xml files */ @@ -776,8 +789,10 @@ public class ProjectCreator { String line; while ((line = in.readLine()) != null) { - for (String key : placeholderMap.keySet()) { - line = line.replace(key, placeholderMap.get(key)); + if (placeholderMap != null) { + for (String key : placeholderMap.keySet()) { + line = line.replace(key, placeholderMap.get(key)); + } } out.write(line); @@ -796,6 +811,85 @@ public class ProjectCreator { destFile); } + /** + * Installs the project icons. + * @param resourceFolder the resource folder + * @param target the target of the project. + * @return true if any icon was installed. + */ + private boolean installIcons(File resourceFolder, IAndroidTarget target) + throws ProjectCreateException { + // query the target for its template directory + String templateFolder = target.getPath(IAndroidTarget.TEMPLATES); + + boolean installedIcon = false; + + installedIcon |= installIcon(templateFolder, "icon_hdpi.png", resourceFolder, "drawable-hdpi"); + installedIcon |= installIcon(templateFolder, "icon_mdpi.png", resourceFolder, "drawable-mdpi"); + installedIcon |= installIcon(templateFolder, "icon_ldpi.png", resourceFolder, "drawable-ldpi"); + + return installedIcon; + } + + /** + * Installs an Icon in the project. + * @return true if the icon was installed. + */ + private boolean installIcon(String templateFolder, String iconName, File resourceFolder, + String folderName) throws ProjectCreateException { + File icon = new File(templateFolder, iconName); + if (icon.exists()) { + File drawable = createDirs(resourceFolder, folderName); + installBinaryFile(icon, new File(drawable, "icon.png")); + return true; + } + + return false; + } + + /** + * Installs a binary file + * @param source the source file to copy + * @param destination the destination file to write + */ + private void installBinaryFile(File source, File destination) { + byte[] buffer = new byte[8192]; + + FileInputStream fis = null; + FileOutputStream fos = null; + try { + fis = new FileInputStream(source); + fos = new FileOutputStream(destination); + + int read; + while ((read = fis.read(buffer)) != -1) { + fos.write(buffer, 0, read); + } + + } catch (FileNotFoundException e) { + // shouldn't happen since we check before. + } catch (IOException e) { + new ProjectCreateException(e, "Failed to read binary file: %1$s", + source.getAbsolutePath()); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + // ignore + } + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + // ignore + } + } + } + + } + /** * Prints a message unless silence is enabled. *