/** * eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the * <e-UCM> research group. * * Copyright 2005-2010 <e-UCM> research group. * * You can access a list of all the contributors to eAdventure at: * http://e-adventure.e-ucm.es/contributors * * <e-UCM> is a research group of the Department of Software Engineering * and Artificial Intelligence at the Complutense University of Madrid * (School of Computer Science). * * C Profesor Jose Garcia Santesmases sn, * 28040 Madrid (Madrid), Spain. * * For more info please visit: <http://e-adventure.e-ucm.es> or * <http://www.e-ucm.es> * * **************************************************************************** * * This file is part of eAdventure, version 2.0 * * eAdventure is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * eAdventure is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with eAdventure. If not, see <http://www.gnu.org/licenses/>. */ package es.eucm.ead.exporter; import es.eucm.ead.engine.resources.R; import es.eucm.ead.tools.java.utils.FileUtils; import org.apache.maven.cli.MavenCli; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class AndroidExporter { public static final String SDK_HOME = "android_home"; public static final String PACKAGE_NAME = "package_name"; public static final String ICON = "icon"; static private Logger logger = LoggerFactory .getLogger(AndroidExporter.class); public static final String TITLE = "title"; private PrintStream stdOut; private PrintStream stdErr; public AndroidExporter() { this.stdOut = System.out; this.stdErr = System.err; } public PrintStream getStdOut() { return stdOut; } public void setStdOut(PrintStream stdOut) { this.stdOut = stdOut; } public PrintStream getStdErr() { return stdErr; } public void setStdErr(PrintStream stdErr) { this.stdErr = stdErr; } public void export(String projectPath, String destination, Properties properties, boolean installAndDeploy) { // Copy android-pom.xml to android folder InputStream apkpom = ClassLoader .getSystemResourceAsStream("android-pom.xml"); InputStream manifest = generateManifest(properties); OutputStream os = null; try { File projectFolder = new File(projectPath); File mavenFolder = FileUtils.createTempDir("eadmaven", ""); File androidFolder = FileUtils.createTempDir("eadandroid", ""); FileUtils.deleteRecursive(androidFolder); androidFolder.mkdirs(); addTitle(mavenFolder, properties); addIcon(mavenFolder, properties); logger.info("Finished adding title & icon to {}", mavenFolder .getAbsolutePath()); FileUtils.copy(apkpom, new FileOutputStream(new File(mavenFolder, "pom.xml"))); FileUtils.copy(manifest, new FileOutputStream(new File(mavenFolder, "AndroidManifest.xml"))); logger.info("Added manifest and pom; now copying game assets..."); // Copy game assets to folder FileUtils .copyRecursive(projectFolder, androidFolder, androidFolder); // Copy engine assets to folder for (String s : R.RESOURCES) { InputStream ris = ClassLoader.getSystemResourceAsStream(s); OutputStream ros = null; try { String fileName = s.substring(s.lastIndexOf('/') + 1); String folder = s.substring(0, s.lastIndexOf('/')); File rf = new File(androidFolder.getAbsolutePath() + '/' + folder); rf.mkdirs(); ros = new FileOutputStream(new File(rf, fileName)); FileUtils.copy(ris, ros); } catch (Exception e) { logger.error("Problem copying resources {}", s, e); } finally { if (ris != null) { ris.close(); } if (ros != null) { ros.close(); } } } logger.info("... game assets & engine assets copied over"); String[] mavenArguments; if (installAndDeploy) { mavenArguments = new String[] { "-Dresources=" + androidFolder.getAbsolutePath(), "-Dandroid.sdk.path=" + properties.getProperty(SDK_HOME), "-X", "clean", "compile", "install", "android:deploy", "android:run" }; } else { mavenArguments = new String[] { "-Dresources=" + androidFolder.getAbsolutePath(), "-Dandroid.sdk.path=" + properties.getProperty(SDK_HOME), "-X", "clean", "compile", "install", }; } logger.info("Starting maven build of game .apk..."); MavenCli maven = new MavenCli(); maven.doMain(mavenArguments, mavenFolder.getAbsolutePath(), getStdOut(), getStdErr()); logger.info("... finished. Now copying .apk to final destination"); // Copy apk to destination if (destination != null) { File destinationFile = new File(destination); if (destinationFile.isDirectory()) { destinationFile = new File(destinationFile, "eAdventuregame.apk"); } else if (!destination.endsWith(".apk")) { destination += ".apk"; destinationFile = new File(destination); } FileUtils.copy(new File(mavenFolder.getAbsolutePath() + "/target", "game-android.apk"), destinationFile); } } catch (Exception e) { logger.error("Error exporting to apk", e); } finally { if (apkpom != null) { try { apkpom.close(); } catch (IOException e) { logger.error("", e); } } if (os != null) { try { os.close(); } catch (IOException e) { logger.error("", e); } } if (manifest != null) { try { manifest.close(); } catch (IOException e) { logger.error("", e); } } } } private void addIcon(File mavenFolder, Properties properties) { String icon = properties.getProperty(ICON); if (icon != null) { File iconFile = new File(icon); if (iconFile.exists()) { File drawable = new File(mavenFolder, "res/drawable/"); drawable.mkdirs(); try { FileUtils.copy(iconFile, new File(drawable, "icon.png")); } catch (IOException e) { logger.error("Error copying {} to {}/icon.png", new Object[] { iconFile, drawable }, e); } } } else { logger.warn("File {} for icon not found; making one up", icon); File drawable = new File(mavenFolder, "res/drawable/"); drawable.mkdirs(); try { int w = 36; int h = w; BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics g = bi.getGraphics(); g.setColor(Color.white); g.fillRect(0, 0, w, h); g.setColor(Color.red); g.drawLine(0, 0, w, h); g.drawLine(0, h, w, 0); ImageIO.write(bi, "png", new File(drawable, "icon.png")); } catch (IOException e) { logger.error("Error making up icon into {}/icon.png", drawable, e); } } } private void addTitle(File mavenFolder, Properties properties) { String title = properties.getProperty(AndroidExporter.TITLE, "eAdventure game"); File values = new File(mavenFolder, "res/values/"); values.mkdirs(); File strings = new File(values, "strings.xml"); Map<String, String> substitutions = new HashMap<String, String>(); substitutions.put("{title}", title); OutputStream os = null; try { os = new FileOutputStream(strings); FileUtils.substituteText(ClassLoader .getSystemResourceAsStream("strings.xml"), os, substitutions); } catch (FileNotFoundException e) { logger.error("Error generating strings.xml", e); } finally { if (os != null) { try { os.close(); } catch (IOException e) { logger.error("Error generation strings.xml", e); } } } } private InputStream generateManifest(Properties properties) { Map<String, String> substitutions = new HashMap<String, String>(); substitutions.put("{package}", properties.getProperty(PACKAGE_NAME, "es.eucm.ead.android.game")); InputStream manifest = ClassLoader .getSystemResourceAsStream("AndroidManifest.xml"); ByteArrayOutputStream os = new ByteArrayOutputStream(); FileUtils.substituteText(manifest, os, substitutions); String result = os.toString(); InputStream is = new ByteArrayInputStream(result.getBytes()); return is; } }